如何对具有共同字段的一片空接口进行排序?
How to Sort a slice of empty Interface that have a field in common?
我有多个结构:
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- 它们都保存在不同的切片中:sliceOfFooStruct、sliceOfBarStruct、sliceofFighterStruct
2- 我遍历每个切片并将它们未排序地插入到公共 var commonSlice []interface{}
切片
3- 然后我需要按 CommonID 将它们分类到那个切片中,这就是我有点卡住的地方。
我正在尝试:
sort.Slice(commonSlice, func(i, j int) bool { return commonSlice[i].CommonID > commonSlice[j].CommonID })
但我遇到了错误
commonSlice[i].CommonID undefined (type interface {} is interface with no methods)
我也尝试过使用 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)
此输出(在 Go Playground 上尝试):
[{21 32 33} {21 32 32} {11 22 31}]
而是创建一个接口来描述访问 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},
}
然后你可以使用GetCommonID()
方法在less()
函数中访问它:
sort.Slice(all, func(i, j int) bool {
return all[i].GetCommonID() > all[j].GetCommonID()
})
这将输出相同的结果,请在 Go Playground.
上尝试
这更干净、更快、可扩展。
为避免重复,您可以将公共字段和方法“外包”到一个结构中,并将其嵌入到您所有的 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()
})
输出是一样的,在Go Playground.
上试试
这还允许您在一个地方 (Common
) 扩展公共字段和方法列表,而无需进一步重复。
我有多个结构:
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- 它们都保存在不同的切片中:sliceOfFooStruct、sliceOfBarStruct、sliceofFighterStruct
2- 我遍历每个切片并将它们未排序地插入到公共 var commonSlice []interface{}
切片
3- 然后我需要按 CommonID 将它们分类到那个切片中,这就是我有点卡住的地方。
我正在尝试:
sort.Slice(commonSlice, func(i, j int) bool { return commonSlice[i].CommonID > commonSlice[j].CommonID })
但我遇到了错误
commonSlice[i].CommonID undefined (type interface {} is interface with no methods)
我也尝试过使用 commonSlice[i].CommonID.(int) 转换类型,但它也不起作用。
也尝试过类似
如果我直接转换被比较的实际结构的类型,但硬编码类型将破坏“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)
此输出(在 Go Playground 上尝试):
[{21 32 33} {21 32 32} {11 22 31}]
而是创建一个接口来描述访问 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},
}
然后你可以使用GetCommonID()
方法在less()
函数中访问它:
sort.Slice(all, func(i, j int) bool {
return all[i].GetCommonID() > all[j].GetCommonID()
})
这将输出相同的结果,请在 Go Playground.
上尝试这更干净、更快、可扩展。
为避免重复,您可以将公共字段和方法“外包”到一个结构中,并将其嵌入到您所有的 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()
})
输出是一样的,在Go Playground.
上试试这还允许您在一个地方 (Common
) 扩展公共字段和方法列表,而无需进一步重复。