英文:
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 Food
s 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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论