在Golang中有一个问题困扰着我。假设我有两个结构体:
type Dog struct {
Name string
Breed string
Age int
}
type Cat struct {
Name string
FavoriteFood string
Age int
}
字符串
当我尝试按Age
对[]*Dog
和[]*Cat
进行排序时,我必须定义两个不同的排序结构,如下所示:
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 {//..}
型
一个自然的想法是实现一些SortableByAge
接口,并使用接口函数创建一个Less
函数。比如:
type SortableByAge interface {
AgeValue() int
}
型
然后:
type SortAnimal []SortableByAge
func (c SortDog) Less(i, j int) bool {
return c[i].AgeValue() < c[j].AgeValue()
}
型
然而,根据:http://golang.org/doc/faq#convert_slice_of_interface
dogs := make([]*Dogs, 0 , 1)
//add dogs here
sort.Sort(SortAnimal(dogs))
型
上面是不可能的。
所以我想知道这种情况下的最佳做法是什么,
有没有其他技术可以减少我一次又一次错过的类似结构的sort.Interface
实现的需要?
编辑:我意识到我的例子很糟糕:(
在真实的情况下,这两个结构是非常不同的,它们之间唯一的共同点是我希望通过一个共同的数值对它们进行排序。
一个更好的例子是:
type Laptop {//...}
type Pizza {//...}
型
这两个结构体唯一的共同点是我希望按价格对它们的一个切片进行排序(啊......在示例中不应该使用Pizza
)。
因此,将它们组合到一个公共结构中并不适用于很多情况。但我们将研究go generate。
4条答案
按热度按时间9rbhqvlz1#
本案例
在这种情况下,你不应该使用两个不同的类型,因为它们是相同的,只需要使用一个公共的
Animal
类型:字符串
输出(Go Playground):
型
通用案例
一般来说,只有当你愿意给予具体类型而使用接口类型时,你才能使用通用的排序实现。
创建希望切片保持的接口类型:
型
你可以有一个通用的实现:
型
您的特定动物类型:
型
您可以在
SortAnim
上实现sort.Interface
:型
使用方法:
型
输出(Go Playground):
型
dgsult0t2#
注意事项:如commit ad26bb5所示,在Go 1.8(2017年第一季度)中,你不必实现
Len()
和Swap()
和Less()
,因为issue 16721已经解析。只需要Less()
,其余的都是通过反射完成的。问题是:
1.绝大多数排序。接口使用切片
1.必须定义一个新的顶级类型
Len
和Swap
方法始终相同1.希望简化常见情况,同时对性能的影响最小
查看新的
sort.go
:字符串
所以只要你有一个
Less()
函数比较两个接口的示例,你就可以对任意数量的接口进行排序。Go 1.18泛型将添加另一个选项,如
nwillc/genfuncs/container/sort.go
所示。型
关于
BiFunction
:型
这只是一个例子,说明了如何实现泛型排序:它不是一个官方的排序(因为泛型在撰写本文时,2022年第一季度,仍然非常新)。
jckbn6z73#
这种情况下的最佳做法是定义
字符串
正如twotwetwo所建议的那样。如果cat和dog足够相似,可以以相同的方式进行排序,那么它们也足够相似,可以成为同一个结构。如果它们在某些方面不同,那么您应该为每个类型重新实现接口。
另一种方法是将
[]*Cat
切片中的所有指针复制到相同大小的[]SortableByAge
切片中。如果要对切片进行排序,则需要O(n*log(n)),因此额外的O(n)不应该是性能问题。第三种选择是,在极少数情况下,您有许多类型,由于某种原因必须是不同的,但仍然具有非常简单的排序功能,您可以使用go generate自动生成它们。
kh212irz4#
在Go 1.21中,他们添加了一个新的包slices。它包含处理泛型类型切片的函数。
slices.SortFunc()
可能会为你简化一些事情,它比sort.Sort()
更快,官方推荐。字符串
请注意,
slices.SortFunc()
并不稳定。为了稳定排序,可以使用slices.SortStableFunc()
,它与slices.SortFunc()
具有相同的签名。