I have this code:
type Iterable[T any] struct { Val T End T Next func() (bool, T) } func acceptStructWithNext[T any](r struct{ Next func() (bool, T) }) { fmt.Println(r) } func main() { iterable := Iterable[int]{ Val: 0, End: 100, Next: func() (bool, int) { return true, 0 }, } acceptStructWithNext[int](iterable) // error is here }
I get this compile error:
Cannot use ‘iterable’ (type Iterable[int]) as the type struct {…}
I thought structural typing was suppose to allow this type of thing - where did I go wrong?
The error you’re encountering is due to the fact that Go has a strong static type system, and it doesn’t support structural typing in the way you are trying to use it.
In your code, Iterable[int] is a distinct type from the anonymous struct used in acceptStructWithNext[int](iterable). Even though the structure of iterable matches the fields and methods of the anonymous struct, they are not considered the same type in Go’s type system.
Iterable[int]
acceptStructWithNext[int](iterable)
iterable
To achieve what you want, you can define an interface with the necessary methods and use that interface in the acceptStructWithNext function:
acceptStructWithNext
type Iterator[T any] interface { Next() (bool, T) } type Iterable[T any] struct { Val T End T Next func() (bool, T) } func (it *Iterable[T]) Next() (bool, T) { return it.Next() } func acceptIterator[T any](it Iterator[T]) { fmt.Println(it) } func main() { iterable := Iterable[int]{ Val: 0, End: 100, Next: func() (bool, int) { return true, 0 }, } acceptIterator(&iterable) }
In this example, I introduced an Iterator interface with a Next method. I also modified the Iterable type to have a method Next that matches the interface. The acceptIterator function now accepts anything that implements the Iterator interface.
Iterator
Next
Iterable
acceptIterator
Note that I changed the receiver type of the Next method to be a pointer receiver (func (it *Iterable[T]) Next() (bool, T)) to match the convention for methods that modify the receiver. If your use case requires non-pointer receivers, you can adjust accordingly.
func (it *Iterable[T]) Next() (bool, T)