Reputation: 14581
Specific example is here: https://play.golang.org/p/ZNmviKWLwe
I have an interface A. I expect all implementations of A to have a certain signature (hence the interface). I expect one of those to return something useful that implements another interface.
type Box interface {
GetToy(int) (*Toy, error)
}
type Toy interface{
Play()
}
type CarBox struct {
Length int
Width int
Height int
toys []*Matchbox
}
type Matchbox struct {}
func (b *CarBox) Size () int {
return b.Length*b.Width*b.Height
}
func (b *CarBox) GetToy(j int) (*Matchbox, error) {
return b.toys[j], nil
}
func (m *Matchbox) Play() {
fmt.Println("Zoom!")
}
But of course, it doesn't work, because GetToy()
returns *Matchbox
and not *Toy
, even though Matchbox
is a perfectly acceptable implementation of Toy
. And, no, it isn't because of the pointers; it gives the same result whether I return *Toy
in GetToy
or just Toy
:
tmp/sandbox721971102/main.go:33:15: cannot use CarBox literal (type CarBox) as type Box in return argument:
CarBox does not implement Box (wrong type for GetToy method)
have GetToy(int) (*Matchbox, error)
want GetToy(int) (*Toy, error)
Obviously my pattern doesn't match how go works. What is the "correct" way to go about doing this?
Upvotes: 3
Views: 7061
Reputation: 12845
Some fixes: https://play.golang.org/p/-mDr5SDZvV
Pointer to interface is extremely rearly required thing. Use interface - it can contain a concrete type.
UPDATE:
If you wish to have a method with pointer receiver like func (b *CarBox) GetToy(j int)
you may return pointer from Tester
function (pay attention to &):
func Tester() Box {
return &CarBox{}
}
This way interface value returned from Tester will conclude a pointer to the CarBox
instance. Thus Go runtime will be able to run methods with pointer receiver. Otherwise there would be only a value not a pointer. So only methods with value receivers could be called.
Upvotes: 1
Reputation: 9116
First of all you almost never need a pointer to an interface type. So GetToy
method signature should be changed to:
type Box interface {
GetToy(int) (Toy, error) // use Toy, not *Toy
}
Now, note that interfaces are satisfied by types implicitly. As a result, by implementing the Play()
method, *Matchbox
implicitly satisfies the Toy
interface (note the *
, the type implementing the Toy
interface is pointer to Matchbox
and not Matchbox
).
This means a value of type *Matchbox
can be substituted for type Toy
. So what remains is to fix the GetToy
method defined on *CarBox
:
func (b *CarBox) GetToy(j int) (Toy, error) {
return b.toys[j], nil
}
Now GetToy
above will return a *Matchbox
which does implement the Toy
interface.
Upvotes: 6