英文:
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
}
但是我无法弄清楚如何创建 spMyInt
或 spMyInt2
类型的变量。
下面的代码无法编译通过:
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't compile
func createSP1[T myInt]() spMyInt[*T] {
var i T
s := S[*T]{t: &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: &i}
return spMyInt[*myInt](s)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论