Go 如何对具有公共字段的空接口片段进行排序?
我有多个结构:Go 如何对具有公共字段的空接口片段进行排序?,go,struct,interface,slice,Go,Struct,Interface,Slice,我有多个结构: type FooStruct struct { ID int Field1 int CommonID int } type BarStruct struct { ID int Field2 int CommonID int } type FighterStruct struct { ID int Field3 int CommonID int } 1-它们都被分成不同的切片:推进切片、推进切片、推进切片 2-我正在迭代每个片段,并将它们
type FooStruct struct {
ID int
Field1 int
CommonID int
}
type BarStruct struct {
ID int
Field2 int
CommonID int
}
type FighterStruct struct {
ID int
Field3 int
CommonID int
}
1-它们都被分成不同的切片:推进切片、推进切片、推进切片
2-我正在迭代每个片段,并将它们未排序地插入到commonvar commonSlice[]接口{}
片段中
3-然后我需要按CommonID将它们分类到该切片中,这就是我被卡住的地方
我正在努力做到:
sort.Slice(commonSlice, func(i, j int) bool { return commonSlice[i].CommonID > commonSlice[j].CommonID })
但我得到了错误
commonSlice[i].CommonID未定义(类型接口{}是没有方法的接口)
我也尝试过使用commonSlice[I].CommonID.(int)强制转换一个类型,但它也不起作用
使用匿名结构和CommonID字段尝试了类似的操作,但没有成功
如果我直接转换被比较的实际结构的类型,我会假设它可以工作,但是硬编码该类型会破坏“commonSlice”的全部用途
这是怎么做到的?我应该做不同的事情吗?因为
commonSlice
的元素类型是interface{}
,所以您不能访问值的任何字段,因为它允许存储任何值,甚至是非结构的值
一种不受欢迎的方法是使用反射来访问CommonID
字段,但这既丑陋又缓慢。以下是它的外观,以供参考:
all := []interface{}{
FooStruct{11, 22, 31},
BarStruct{21, 32, 33},
FighterStruct{21, 32, 32},
}
sort.Slice(all, func(i, j int) bool {
commonID1 := reflect.ValueOf(all[i]).FieldByName("CommonID").Int()
commonID2 := reflect.ValueOf(all[j]).FieldByName("CommonID").Int()
return commonID1 > commonID2
})
fmt.Println(all)
这将输出(在上尝试):
而是创建一个接口,描述访问CommonID
字段的方法:
type HasCommonID interface {
GetCommonID() int
}
并使您的struts实现此接口:
func (f FooStruct) GetCommonID() int { return f.CommonID }
func (b BarStruct) GetCommonID() int { return b.CommonID }
func (f FighterStruct) GetCommonID() int { return f.CommonID }
all := []HasCommonID{
FooStruct{11, 22, 31},
BarStruct{21, 32, 33},
FighterStruct{21, 32, 32},
}
并将您的值存储在此界面的一部分中:
func (f FooStruct) GetCommonID() int { return f.CommonID }
func (b BarStruct) GetCommonID() int { return b.CommonID }
func (f FighterStruct) GetCommonID() int { return f.CommonID }
all := []HasCommonID{
FooStruct{11, 22, 31},
BarStruct{21, 32, 33},
FighterStruct{21, 32, 32},
}
然后您可以使用GetCommonID()
方法在less()
函数中访问它:
sort.Slice(all, func(i, j int) bool {
return all[i].GetCommonID() > all[j].GetCommonID()
})
这将输出相同的结果,请在上尝试
这是更干净,更快,可扩展
为了避免重复,您可以将公共字段和方法“外包”到结构中,并将其嵌入到所有struts中:
type Common struct {
CommonID int
}
func (c Common) GetCommonID() int { return c.CommonID }
type FooStruct struct {
ID int
Field1 int
Common
}
type BarStruct struct {
ID int
Field2 int
Common
}
type FighterStruct struct {
ID int
Field3 int
Common
}
注意:GetCommonID()
只定义了一次,对于Common
,其他类型不需要添加它。然后使用它:
all := []HasCommonID{
FooStruct{11, 22, Common{31}},
BarStruct{21, 32, Common{33}},
FighterStruct{21, 32, Common{32}},
}
sort.Slice(all, func(i, j int) bool {
return all[i].GetCommonID() > all[j].GetCommonID()
})
输出相同,请在上尝试
这还允许您在单个位置(
common
)扩展公共字段和方法列表,而无需进一步重复。因为commonSlice
的元素类型是interface{}
,所以您不能访问值的任何字段,因为它允许存储任何值,即使是非结构的值
一种不受欢迎的方法是使用反射来访问CommonID
字段,但这既丑陋又缓慢。以下是它的外观,以供参考:
all := []interface{}{
FooStruct{11, 22, 31},
BarStruct{21, 32, 33},
FighterStruct{21, 32, 32},
}
sort.Slice(all, func(i, j int) bool {
commonID1 := reflect.ValueOf(all[i]).FieldByName("CommonID").Int()
commonID2 := reflect.ValueOf(all[j]).FieldByName("CommonID").Int()
return commonID1 > commonID2
})
fmt.Println(all)
这将输出(在上尝试):
而是创建一个接口,描述访问CommonID
字段的方法:
type HasCommonID interface {
GetCommonID() int
}
并使您的struts实现此接口:
func (f FooStruct) GetCommonID() int { return f.CommonID }
func (b BarStruct) GetCommonID() int { return b.CommonID }
func (f FighterStruct) GetCommonID() int { return f.CommonID }
all := []HasCommonID{
FooStruct{11, 22, 31},
BarStruct{21, 32, 33},
FighterStruct{21, 32, 32},
}
并将您的值存储在此界面的一部分中:
func (f FooStruct) GetCommonID() int { return f.CommonID }
func (b BarStruct) GetCommonID() int { return b.CommonID }
func (f FighterStruct) GetCommonID() int { return f.CommonID }
all := []HasCommonID{
FooStruct{11, 22, 31},
BarStruct{21, 32, 33},
FighterStruct{21, 32, 32},
}
然后您可以使用GetCommonID()
方法在less()
函数中访问它:
sort.Slice(all, func(i, j int) bool {
return all[i].GetCommonID() > all[j].GetCommonID()
})
这将输出相同的结果,请在上尝试
这是更干净,更快,可扩展
为了避免重复,您可以将公共字段和方法“外包”到结构中,并将其嵌入到所有struts中:
type Common struct {
CommonID int
}
func (c Common) GetCommonID() int { return c.CommonID }
type FooStruct struct {
ID int
Field1 int
Common
}
type BarStruct struct {
ID int
Field2 int
Common
}
type FighterStruct struct {
ID int
Field3 int
Common
}
注意:GetCommonID()
只定义了一次,对于Common
,其他类型不需要添加它。然后使用它:
all := []HasCommonID{
FooStruct{11, 22, Common{31}},
BarStruct{21, 32, Common{33}},
FighterStruct{21, 32, Common{32}},
}
sort.Slice(all, func(i, j int) bool {
return all[i].GetCommonID() > all[j].GetCommonID()
})
输出相同,请在上尝试
这还允许您在单个位置(
common
)扩展公共字段和方法列表,而无需进一步重复。。非常感谢。哦,很好。非常感谢。“我应该以不同的方式做事吗?”是的,不要使用空界面。是的,icza已经回答了这个问题,我不再使用自定义界面。无论如何,感谢您的巨大贡献。“我应该以不同的方式做事吗?”是的,不要使用空界面。是的,icza已经回答了,我不再使用自定义界面。无论如何,感谢您的巨大贡献。