I am playing with generics in beta release of go 1.18. Create function in example below should create new instance of *T
(therefore *Apple
). I tried to use reflect package for that, but without luck.
Can you please show me how I can change function Create
from the example below so that it creates instance of T
instead of returning nil and crashing my example?
type FruitFactory[T any] struct{}
func (f FruitFactory[T]) Create() *T {
//how to create non-nil fruit here?
return nil
}
type Apple struct {
color string
}
func example() {
appleFactory := FruitFactory[Apple]{}
apple := appleFactory.Create()
//panics because nil pointer access
apple.color = "red"
}
CodePudding user response:
Since you are instantiating FruitFactory
with a non-pointer type (Apple
), you can just declare a typed variable and return its address:
func (f FruitFactory[T]) Create() *T {
var a T
return &a
}
Or:
func (f FruitFactory[T]) Create() *T {
return new(T)
}
Playground: https://gotipplay.golang.org/p/IJErmO1mrJh
If you want to instantiate FruitFactory
with a pointer type and still avoid segmentation faults, things get more complicated. Basically you have to take advantage of type inference to declare a variable of the non-pointer type in the method body and convert that to the pointer type.
// constraining a type to its pointer type
type Ptr[T any] interface {
*T
}
// the first type param will match pointer types and infer U
type FruitFactory[T Ptr[U], U any] struct{}
func (f FruitFactory[T,U]) Create() T {
// declare var of non-pointer type. this is not nil!
var a U
// address it and convert to pointer type (still not nil)
return T(&a)
}
type Apple struct {
color string
}
func main() {
// instantiating with ptr type
// second type param U is inferred from the first
appleFactory := FruitFactory[*Apple]{}
apple := appleFactory.Create()
// all good
apple.color = "red"
fmt.Println(apple) // &{red}
}
Playground: https://gotipplay.golang.org/p/07nUGI-xP0O