Probably a golang beginner's question :)
I'm facing following compiler error when trying to compile the code below.
I want to implement an object store for different types (here A and B) sharing a common ID field. Following the DRY idea, I want to implement the store using generics.
When adding an object, I want to set its ID field using the GS interface (the actual code is a bit more complex of course), but the compiler does not want me to do that.
./prog.go:29:7: item.SetId undefined (type *T is pointer to type parameter, not type parameter)
./prog.go:34:24: A does not implement GS (SetId method has pointer receiver)
Is there a recommended way to solve this? Thanks in advance!!
package main
import "fmt"
type A struct {
ID string
AMember string
}
type B struct {
ID string
BMember string
}
type GS interface {
Id() string
SetId(string)
}
func (s A) Id() string { return s.ID }
func (s *A) SetId(i string) { s.ID = i }
func (s B) Id() string { return s.ID }
func (s *B) SetId(i string) { s.ID = i }
type MyStore[T GS] struct {
values map[string]*T
}
func (s *MyStore[T]) add(item *T) {
item.SetId("aa")
s.values["aa"] = item
}
func main() {
var storeA = &MyStore[A]{}
storeA.values = make(map[string]*A)
a := &A{}
storeA.add(a)
fmt.Println(a.Id())
}
CodePudding user response:
The reason this instantiation &MyStore[A]{}
fails is clearly reported by the error message:
A does not implement GS (SetId method has pointer receiver)
In other words SetId()
is declared on *A
, and not A
. Therefore you should instantiate MyStore
with *A
:
var storeA = &MyStore[*A]{}
Then change the occurrences of *T
in the struct/method definition to T
:
type MyStore[T GS] struct {
values map[string]T // just T instead of *T
}
func (s *MyStore[T]) add(item T) {
}
Upon instantiation with *A
the type of the field would become equivalent to map[string]*A
thus making the assignment storeA.values = make(map[string]*A)
valid, and the method signature to add(item *A)
thus allowing storeA.add(&A{})
.
Fixed playground: https://gotipplay.golang.org/p/dcUVJ5YQK_b