Lic*_*ich 8 coding-style interface go slice
Golang有一个问题困扰我.说我有两个结构:
type Dog struct {
Name string
Breed string
Age int
}
type Cat struct {
Name string
FavoriteFood string
Age int
}
Run Code Online (Sandbox Code Playgroud)
当我尝试进行排序[]*Dog和[]*Cat通过Age,我必须定义2个不同类型的结构,如:
type SortCat []*Cat
func (c SortCat) Len() int {//..}
func (c SortCat) Swap(i, j int) {//..}
func (c SortCat) Less(i, j int) bool {//..}
type SortDog []*Dog
func (c SortDog) Len() int {//..}
func (c SortDog) Swap(i, j int) {//..}
func (c SortDog) Less(i, j int) bool {//..}
Run Code Online (Sandbox Code Playgroud)
一个自然的想法是使用接口函数实现一些SortableByAge接口并创建一个Less函数.喜欢:
type SortableByAge interface {
AgeValue() int
}
Run Code Online (Sandbox Code Playgroud)
然后:
type SortAnimal []SortableByAge
func (c SortDog) Less(i, j int) bool {
return c[i].AgeValue() < c[j].AgeValue()
}
Run Code Online (Sandbox Code Playgroud)
但是,根据:http: //golang.org/doc/faq#convert_slice_of_interface
dogs := make([]*Dogs, 0 , 1)
//add dogs here
sort.Sort(SortAnimal(dogs))
Run Code Online (Sandbox Code Playgroud)
以上是不可能的.
所以我想知道这个案例的最佳做法是什么
有没有其他技术可以减少sort.Interface我一次又一次地实现类似结构的需要?
编辑:我意识到我的例子很可怕:(
在现实生活中,这两个结构是非常不同的,它们之间唯一的共同点是我希望用一个共同的数值对它们进行排序.
一个更好的例子是:
type Laptop {//...}
type Pizza {//...}
Run Code Online (Sandbox Code Playgroud)
这两个结构的唯一共同之处在于,我希望Pizza按价格对它们进行分类(agh ...不应该在示例中使用).
因此,将它们与一个通用结构相结合并不适用于很多情况.但是会考虑去生成.
icz*_*cza 11
在这种特定情况下,您不应该使用两种不同的类型,因为它们是相同的,只需使用一个通用Animal类型:
type Animal struct {
Name string
Age int
}
func (a Animal) String() string { return fmt.Sprintf("%s(%d)", a.Name, a.Age) }
type SortAnim []*Animal
func (c SortAnim) Len() int { return len(c) }
func (c SortAnim) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c SortAnim) Less(i, j int) bool { return c[i].Age < c[j].Age }
func main() {
dogs := []*Animal{&Animal{"Max", 4}, &Animal{"Buddy", 3}}
cats := []*Animal{&Animal{"Bella", 4}, &Animal{"Kitty", 3}}
fmt.Println(dogs)
sort.Sort(SortAnim(dogs))
fmt.Println(dogs)
fmt.Println(cats)
sort.Sort(SortAnim(cats))
fmt.Println(cats)
}
Run Code Online (Sandbox Code Playgroud)
输出(Go Playground):
[Max(4) Buddy(3)]
[Buddy(3) Max(4)]
[Bella(4) Kitty(3)]
[Kitty(3) Bella(4)]
Run Code Online (Sandbox Code Playgroud)
通常,如果您愿意放弃具体类型并使用接口类型,则只能使用通用排序实现.
创建希望切片保留的接口类型:
type Animal interface {
Name() string
Age() int
}
Run Code Online (Sandbox Code Playgroud)
你可以有一个共同的实现:
type animal struct {
name string
age int
}
func (a *animal) Name() string { return a.name }
func (a *animal) Age() int { return a.age }
func (a animal) String() string { return fmt.Sprintf("%s(%d)", a.name, a.age) }
Run Code Online (Sandbox Code Playgroud)
您的特定动物类型:
type Dog struct {
animal // Embed animal (its methods and fields)
}
type Cat struct {
animal // Embed animal (its methods and fields)
}
Run Code Online (Sandbox Code Playgroud)
您可以实现sort.Interface的SortAnim:
type SortAnim []Animal
func (c SortAnim) Len() int { return len(c) }
func (c SortAnim) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c SortAnim) Less(i, j int) bool { return c[i].Age() < c[j].Age() }
Run Code Online (Sandbox Code Playgroud)
使用它:
dogs := SortAnim{&Dog{animal{"Max", 4}}, &Dog{animal{"Buddy", 3}}}
cats := SortAnim{&Cat{animal{"Bella", 4}}, &Cat{animal{"Kitty", 3}}}
fmt.Println(dogs)
sort.Sort(SortAnim(dogs))
fmt.Println(dogs)
fmt.Println(cats)
sort.Sort(SortAnim(cats))
fmt.Println(cats)
Run Code Online (Sandbox Code Playgroud)
输出(Go Playground):
[Max(4) Buddy(3)]
[Buddy(3) Max(4)]
[Bella(4) Kitty(3)]
[Kitty(3) Bella(4)]
Run Code Online (Sandbox Code Playgroud)
注:如图提交ad26bb5,在Go 1.8(Q1 2017),你不会有落实Len(),并Swap()与Less()自发行16721得到解决.只有Less()需要,其余的都是通过反思完成的.
问题是:
- 绝大多数sort.Interface使用切片
- 必须定义一个新的顶级类型
Len和Swap方法总是一样的- 想要使普通案例更简单,性能最低
看到新的sort.go:
// Slice sorts the provided slice given the provided less function.
//
// The sort is not guaranteed to be stable. For a stable sort, use
// SliceStable.
//
// The function panics if the provided interface is not a slice.
func Slice(slice interface{}, less func(i, j int) bool) {
rv := reflect.ValueOf(slice)
swap := reflect.Swapper(slice)
length := rv.Len()
quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length))
}
Run Code Online (Sandbox Code Playgroud)
因此,只要您有一个Less()函数比较两个关于接口的实例,您就可以对所述公共接口进行任意数量的结构排序.