通过Go(go 1.18)泛型创建一个新的类型化值对象。

huangapple go评论107阅读模式
英文:

Create new object of typed value via Go (go 1.18) generics

问题

我正在使用Go 1.18的beta版本中的泛型进行实验。下面的示例中的Create函数应该创建一个新的*T实例(也就是*Apple)。我尝试使用反射包来实现,但没有成功。

请问你能否告诉我如何修改下面示例中的Create函数,以便它创建T的实例而不是返回nil并导致示例崩溃?

  1. type FruitFactory[T any] struct{}
  2. func (f FruitFactory[T]) Create() *T {
  3. //在这里如何创建非nil的水果?
  4. return nil
  5. }
  6. type Apple struct {
  7. color string
  8. }
  9. func example() {
  10. appleFactory := FruitFactory[Apple]{}
  11. apple := appleFactory.Create()
  12. //因为空指针访问而导致恐慌
  13. apple.color = "red"
  14. }
英文:

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?

  1. type FruitFactory[T any] struct{}
  2. func (f FruitFactory[T]) Create() *T {
  3. //how to create non-nil fruit here?
  4. return nil
  5. }
  6. type Apple struct {
  7. color string
  8. }
  9. func example() {
  10. appleFactory := FruitFactory[Apple]{}
  11. apple := appleFactory.Create()
  12. //panics because nil pointer access
  13. apple.color = "red"
  14. }

答案1

得分: 18

由于您正在使用非指针类型(Apple)实例化FruitFactory,您可以只声明一个带有类型的变量并返回其地址:

  1. func (f FruitFactory[T]) Create() *T {
  2. var a T
  3. return &a
  4. }

或者:

  1. func (f FruitFactory[T]) Create() *T {
  2. return new(T)
  3. }

Playground: https://gotipplay.golang.org/p/IJErmO1mrJh

如果您想要使用指针类型实例化FruitFactory并且仍然避免段错误,情况会变得更加复杂。基本上,您必须在方法体中声明一个非指针类型的变量,并将其转换为指针类型。

  1. // 将类型约束为其指针类型
  2. type Ptr[T any] interface {
  3. *T
  4. }
  5. // 第一个类型参数将匹配指针类型并推断出U
  6. type FruitFactory[T Ptr[U], U any] struct{}
  7. func (f FruitFactory[T, U]) Create() T {
  8. // 声明非指针类型的变量。这不是nil!
  9. var a U
  10. // 取其地址并转换为指针类型(仍然不是nil)
  11. return T(&a)
  12. }
  13. type Apple struct {
  14. color string
  15. }
  16. func main() {
  17. // 使用指针类型进行实例化
  18. appleFactory := FruitFactory[*Apple, Apple]{}
  19. apple := appleFactory.Create()
  20. // 一切正常
  21. apple.color = "red"
  22. fmt.Println(apple) // &{red}
  23. }

Playground: https://gotipplay.golang.org/p/07nUGI-xP0O

编辑,2022年3月:已禁用定义类型的类型推断,因此第二个示例代码不再编译。保留原始代码以供参考。您必须提供所有类型参数:FruitFactory[*Apple, Apple]{},这使得代码相当冗长。对于函数,类型推断仍然正常工作。

英文:

Since you are instantiating FruitFactory with a non-pointer type (Apple), you can just declare a typed variable and return its address:

  1. func (f FruitFactory[T]) Create() *T {
  2. var a T
  3. return &a
  4. }

Or:

  1. func (f FruitFactory[T]) Create() *T {
  2. return new(T)
  3. }

Playground: https://gotipplay.golang.org/p/IJErmO1mrJh

<hr>

If you want to instantiate FruitFactory with a pointer type and still avoid segmentation faults, things get more complicated. Basically you have to <strike>take advantage of type inference to</strike> declare a variable of the non-pointer type in the method body and convert that to the pointer type.

  1. // constraining a type to its pointer type
  2. type Ptr[T any] interface {
  3. *T
  4. }
  5. // the first type param will match pointer types and infer U
  6. type FruitFactory[T Ptr[U], U any] struct{}
  7. func (f FruitFactory[T,U]) Create() T {
  8. // declare var of non-pointer type. this is not nil!
  9. var a U
  10. // address it and convert to pointer type (still not nil)
  11. return T(&amp;a)
  12. }
  13. type Apple struct {
  14. color string
  15. }
  16. func main() {
  17. // instantiating with ptr type
  18. appleFactory := FruitFactory[*Apple, Apple]{}
  19. apple := appleFactory.Create()
  20. // all good
  21. apple.color = &quot;red&quot;
  22. fmt.Println(apple) // &amp;{red}
  23. }

Playground: https://gotipplay.golang.org/p/07nUGI-xP0O

EDIT, March 2022: type inference for defined types has been disabled, so the second playground doesn't compile anymore. Leaving the original one for reference. You must supply all type parameters: FruitFactory[*Apple, Apple]{}, which does make it quite verbose. Type inference works normally for functions.

huangapple
  • 本文由 发表于 2021年12月17日 22:40:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/70394814.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定