英文:
Go: Comparison in maps of interface types
问题
假设我有很多不同的结构类型,它们都满足一个接口Food。
type Food interface {
    Name() string
    Tastiness() int
}
type fruit struct {
    species  string
    numSeeds int
}
type vegetable struct {
    commonName string
    weight  int
}
func (f *fruit) Name() string       { return f.species }
func (f *fruit) Tastiness() int     { return 100 - f.numSeeds }
func (v *vegetable) Name() string   { return v.commonName }
func (v *vegetable) Tastiness() int { return 1 }
满足Food接口的结构体使用的是具有指针接收器的函数,因为我经常传递它们,如果没有指针,这将变得很麻烦。
通常,我想要比较food1和food2,所以我构建了类似于foodmap := map[Food]bool的映射。我真正想要检查的是底层结构体是否相同。但是,由于始终是指针满足接口,如果我创建了两个相同类型的fruit或vegetable,我无法使用映射或列表进行相等性或存在性测试。
比较Food的最佳方法是不使用map[Food]bool,而是使用类似于map[FoodKey]的东西,其中任何满足Food的结构体都提供一个FoodKey() comparisonStruct方法,该方法返回一个专门用于比较的结构体。
英文:
Let's say I have a lot of different struct types which all satisfy an interface, Food.
type Food interface {
	Name() string
	Tastiness() int
}
type fruit struct {
	species  string
	numSeeds int
}
type vegetable struct {
	commonName string
	weight  int
}
func (f *fruit) Name() string       { return f.species }
func (f *fruit) Tastiness() int     { return 100 - f.numSeeds }
func (v *vegetable) Name() string   { return v.commonName }
func (v *vegetable) Tastiness() int { return 1 }
The structs that satisfy the Food interface do so with functions that are pointer receivers because I pass them around often, which is unwieldy without pointers.
Often, I want to make comparisons between food1 and food2, and so I construct maps that look like foodmap := map[Food]bool. What I really want to check is if the underlying structs are the same thing. But, because it's always pointers that are satisfying the interface, I can't do equality or presence tests using maps or lists if I create two of the same kind of fruit or vegetable, for example.
Is the best way to compare Foods to not use map[Food]bool and instead use something like map[FoodKey], where any struct that satsifies Food provides a FoodKey() comparisonStruct method that returns a struct meant strictly for comparison?
答案1
得分: 1
最好的比较食物的方法是不使用map[Food]bool,而是使用类似map[FoodKey]的结构,其中任何满足Food接口的结构都提供一个FoodKey() comparisonStruct方法,该方法返回一个严格用于比较的结构体。
我怀疑这是一个更好的方法,考虑到以下几点:
- 
比较接口是慢的(issue 6105)
 - 
您可能需要区分您正在比较的接口实例中包含的实际类型。
 
英文:
> Is the best way to compare Foods to not use map[Food]bool and instead use something like map[FoodKey], where any struct that satsifies Food provides a FoodKey() comparisonStruct method that returns a struct meant strictly for comparison?
I suspect it is a better approach, considering:
- 
comparing interface is slow (issue 6105)
 - 
(and that supposes comparison operators are defined: see Map Types)
 - 
using an
Equaler(as in this thread) isn't easy - 
you might need to distinguish between the actual types included in the interface instances you are comparing.
 
答案2
得分: 1
我相信在这里最有效的方法是在你的接口中添加一个额外的函数,比如Is(f Food) bool,它很容易实现,没有使用反射或比较接口或使用映射的开销。
示例:
type Food interface {
    Name() string
    Tastiness() int
    Is(f Food) bool
}
//....
func (*fruit) Is(f Food) bool   { _, ok := f.(*fruit); return ok }
//....
func (*vegetable) Is(f Food) bool   { _, ok := f.(*vegetable); return ok }
英文:
I believe the most efficient path here is to add an extra function to your interface like Is(f Food) bool, it's easy to implement, no overhead of using reflection or comparing interfaces or using a map somewhere.
Example:
type Food interface {
	Name() string
	Tastiness() int
	Is(f Food) bool
}
//....
func (*fruit) Is(f Food) bool   { _, ok := f.(*fruit); return ok }
//....
func (*vegetable) Is(f Food) bool   { _, ok := f.(*vegetable); return ok }
答案3
得分: 0
你有两种方法来确定或比较接口的底层结构。
1- 使用 reflect 包,具体来说是 reflect.TypeOf 函数,它将返回接口的动态类型,例如:
x := Food(fruit{"banana", 0})
y := Food(vegetable{"potato", 45})
return reflect.TypeOf(x) == reflect.TypeOf(y)
这段代码将返回 false。
2- 使用类型断言或 类型切换,例如:
value, ok := yourInterface.(possibleType)
英文:
You have two options to determine or compare the underlying structs of interfaces.
1- Use the reflect package, specifically the reflect.TypeOf function, which will return the dynamic type of the interface, such as:
x := Food(fruit{"banana", 0})
y := Food(vegetable{"potato, 45})
return reflect.TypeOf(x) == reflect.TypeOf(y)
This piece of code will return false.
2- Use type assertions or a type switch, such as:
value, ok := yourInterface.(possibleType)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论