创建具有指向类型参数的指针的通用类型实例。

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

Create instance of generic type with pointer to type parameter

问题

给定以下类型定义:

type N interface{ ~int | ~float32 | ~float64 }

type S[T any] struct {
	t T
}

type myInt int

type pSpMyInt[T myInt] *S[*T]
type spMyInt[T *myInt,] S[T]
type spMyInt2[T myInt] S[*T]

我可以使用以下代码创建一个 pSpMyInt 类型的变量:

func createPS[T myInt]() pSpMyInt[T] {
	var i T
	s := S[*T]{t: &i}
	return &s
}

但是我无法弄清楚如何创建 spMyIntspMyInt2 类型的变量。

下面的代码无法编译通过:

func createSP[T myInt]() spMyInt2[T] {
	var i T
	s := S[*T]{t: &i}
	return s
}

编译错误为:cannot use s (variable of type S[*T]) as type spMyInt2[T] in return statement

英文:

Given these type definitions:

type N interface{ ~int | ~float32 | ~float64 }

type S[T any] struct {
	t T
}

type myInt int

type pSpMyInt[T myInt] *S[*T]
type spMyInt[T *myInt,] S[T]
type spMyInt2[T myInt] S[*T]

I can create a var of type pSpMyInt with

func createPS[T myInt]() pSpMyInt[T] {
	var i T
	s := S[*T]{t: &i}
	return &s
}

But I can not figure out how to create vars of spMyInt or spMyInt2.

This

func createSP[T myInt]() spMyInt2[T] {
	var i T
	s := S[*T]{t: &i}
	return s
}

fails to compile
cannot use s (variable of type S[*T]) as type spMyInt2[T] in return statement.

答案1

得分: 3

首先,不要使用精确的类型参数约束。这几乎没有意义。当你将一个函数声明为createPS[T myInt]()时,类型参数的类型集合的基数为1,因此它只能通过myInt来实例化。你可以像下面这样重新编写函数:

func createPS() pSpMyInt[myInt] {
    var i myInt
    s := S[*myInt]{t: &i}
    return &s
}

解决了这个问题之后:

类型S[*T]spMyInt2[T]并不相同。然而,由于spMyInt2[T]的底层类型是S[*T],你可以简单地进行转换:

func createSP2[T myInt]() spMyInt2[T] {
    var i T
    s := S[*T]{t: &i}
    return spMyInt2[T](s) // 转换
}

至于type spMyInt[T *myInt,] S[T](逗号不是拼写错误,而是为了避免解析歧义),事情并不那么简单。

问题在于类型参数不是它的类型约束。因此,类型字面量不能用于实例化不同的未命名类型字面量。明确一下:

// 无法编译的天真尝试
func createSP1[T myInt]() spMyInt[*T] {
    var i T
    s := S[*T]{t: &i}
    return spMyInt[*T](s)
}

你可能会认为spMyInt[T *myInt]的类型参数受限于*myInt,函数T受限于基本类型myInt因此*T应该满足T *myInt。但是由于类型字面量*T*myInt并不等价,所以实际上你不能为type spMyInt[T *myInt,] S[T]编写一个通用的构造函数。

不过,你很幸运,因为类型约束的基数为一。所以你可以直接移除类型参数:

func createSP1() spMyInt[*myInt] {
    var i myInt
    s := S[*myInt]{t: &i}
    return spMyInt[*myInt](s)
}
英文:

First of all, do NOT use exact type parameter constraints. It almost never makes sense. When you declare a function as createPS[T myInt](), the type parameter type set has cardinality 1, so it can effectively be instantiated only and ever by myInt. You could rewrite the function like the following just as fine:

func createPS() pSpMyInt[myInt] {
    var i myInt
    s := S[*myInt]{t: &i}
    return &s
}

With that out of the way:

The type S[*T] is just not the same as spMyInt2[T]. However, since spMyInt2[T]'s underlying type is S[*T], you can simply convert:

func createSP2[T myInt]() spMyInt2[T] {
	var i T
	s := S[*T]{t: &i}
	return spMyInt2[T](s) // conversion
}

<hr>

As for type spMyInt[T *myInt,] S[T] (where the comma is not a typo but is needed to avoid a parsing ambiguity), the thing isn't that simple.

The problem is that a type parameter is not its type constraint. Therefore type literals can't be used to instantiate different unnamed type literals. To be clear:

// naive attempt that doesn&#39;t compile
func createSP1[T myInt]() spMyInt[*T] {
	var i T
	s := S[*T]{t: &amp;i}
	return spMyInt[*T](s)
}

You might think that spMyInt[T *myInt] has a type parameter constrained to *myInt and the function T is constrained by the base type myInt, therefore *T should satisfy T *myInt. This is not correct for the apparently unobvious reason that the type literal *T is not equivalent to *myInt. So actually you can't write a generic constructor for type spMyInt[T *myInt,] S[T].

However you are in luck because the type constraint had cardinality one. So you can just remove the type parameter:

func createSP1() spMyInt[*myInt] {
	var i myInt
	s := S[*myInt]{t: &amp;i}
	return spMyInt[*myInt](s)
}

huangapple
  • 本文由 发表于 2022年11月18日 16:24:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/74486774.html
匿名

发表评论

匿名网友

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

确定