Given there's a generic interface:
type Packet interface {
Content() int
}
type Recycler[T any] interface {
Get() *T
}
and their implementation:
type packet struct {
content int
}
type BaseRecycler[T any] struct {
t T
}
its impossible to convert the implementation to the interface:
r := &BaseRecycler[packet]{}
r1 := r.(Recycler[Packet])
fmt.Println(r3.Get().Content()) // compile error: Unresolved reference 'Content'
here is a live code example: https://go.dev/play/p/qbnYfyDd22A
The error is because the Packet
interface align with the *packet
instead of packet
. Could anyone suggest how to handle this?
You are assuming covariance in type parameters, which Go does not have - types must match exactly. You would need variance annotations like Kotlins in
and out
or Javas wildcards for that.
As the FAQ states:
In Go method types must match exactly, [...]. Programmers who want covariant result types are often trying to express a type hierarchy through interfaces. In Go it’s more natural to have a clean separation between interface and implementation.
To be a little more concrete, you could implement your packet
like (Go Playground):
type packet struct {
content int
}
func (p packet) Content() int {
return p.content
}
and then an interface abstracting that:
type Packet interface {
Content() int
}
Also the BaseRecycler
:
type BaseRecycler[T any] struct {
t T
}
func (b BaseRecycler[T]) Get() T {
return b.t
}
and an abstraction thereof:
type Recycler[T any] interface {
Get() T
}
Note some simplifications: The methods don't have pointer receivers (they serve no purpose in this example) and BaseRecycler
does return a type, not an address.
Now you can simply use that:
var r Recycler[Packet] = BaseRecycler[Packet]{t: packet{}}
fmt.Println(r.Get().Content())
Also, you could define a PacketRecycler
which has a concrete packet
type and is not generic:
type PacketRecycler struct {
t packet
}
func (p PacketRecycler) Get() Packet {
return p.t
}
and use it in an identical fashion:
var r1 Recycler[Packet] = PacketRecycler{}
fmt.Println(r1.Get().Content())