rxmnnxfpvg
rxmnnxfpvg

Reputation: 31033

Go: Comparison in maps of interface types

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?

Upvotes: 1

Views: 1547

Answers (3)

OneOfOne
OneOfOne

Reputation: 99431

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 }

playground

Upvotes: 1

Marc
Marc

Reputation: 1820

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)

Upvotes: 0

VonC
VonC

Reputation: 1330092

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:

Upvotes: 1

Related Questions