英文:
Convert a type (int, float etc) to `T` [go1.18]
问题
场景:
支持泛型的Go 1.18
问题:
无法将数字转换为泛型。
解释:
我正在尝试将我的“通用目的”库转换为支持泛型。我遇到了数字转换错误的问题。
我定义了一个包,其中包含所有数字类型,如下所示:
package types
type Number interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | uintptr | float32 | float64
}
我没有特别的问题要处理泛型。我唯一没有理解的是:
如何将定义的类型(比如int
)转换为泛型?
让我们假设以下示例:
// FindIndexValue是委托函数,用于获取给定值在输入数组中的索引。
func FindIndexValue[T types.Number](array []T, value T) []T {
var indexs []T
for i := range array {
if array[i] == value {
indexs = append(indexs, i)
}
}
return indexs
}
在上面的代码片段中,错误出现在以下行:
...
for i := range array {
...
}
这是因为range
内置函数遍历数组并返回给定位置的索引(int
类型)。
问题是:
如何将定义的类型(在本例中为int
)转换为泛型T
?
错误:
cannot use i (variable of type int) as type T in argument to append
英文:
Scenario:
Go 1.18 that support generics
Problem:
Unable to convert a number into generics.
Explanation:
I'm trying to port my general purpose
library to support generics. I'm dealing with number cast error.
I've defined a package that contains all the number types as following:
package types
type Number interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | uintptr | float32 | float64
}
I've no particular problem to deal with generics. The only thing that I've not understood is:
How to convert a defined type (like int
) to a generic?
Let's assume the following example:
// FindIndexValue is delegated to retrieve the index of the given value into the input array.
func FindIndexValue[T types.Number](array []T, value T) []T {
var indexs []T
for i := range array {
if array[i] == value {
indexs = append(indexs, i)
}
}
return indexs
}
In the above snippet, the error is located in the line:
...
for i := range array {
...
}
This because the range
builtin iterate the array and return the index (int
) of the given position.
The question is:
How can I convert the defined type (int
in this case) to the generic T
?
Error:
cannot use i (variable of type int) as type T in argument to append
答案1
得分: 6
你可以像平常一样将一个值转换为参数类型。
根据提案类型转换:
在一个具有两个类型参数
From
和To
的函数中,如果From
的约束类型集中的所有类型都可以转换为To
的约束类型集中的所有类型,那么可以将类型为From
的值转换为类型为To
的值。
在这种情况下,你实际上没有一个 From
,因为它是切片索引 int
;目标类型将是 T
(尽管这可能不是你想要的,下面会解释为什么)。当然,int
可以转换为 T
的类型集,因为它只包括数值类型(尽管在 int8
或 float64
的情况下可能会有截断或精度损失)。
indexs = append(indexs, T(i))
然而,你的程序将索引的切片声明为 []T
,这意味着将泛型函数实例化为:
is := FindIndexValue([]float64{1,5,7,9}, float64(9))
将得到一个类型为 []float64
的结果。由于返回的值是切片索引,它们始终是 int
,这没有太多意义。
更好的做法是简单地返回 []int
:
func FindIndexValue[T Number](array []T, value T) []int {
var indices []int
for i := range array {
// 匹配泛型类型的切片项
if array[i] == value {
// 将切片索引存储为 int
indices = append(indexs, i)
}
}
return indices
}
Playground: https://gotipplay.golang.org/p/EykXppG2qJa
英文:
You convert a value to a parameter type as you would normally do.
From the proposal Type conversions:
> In a function with two type parameters From
and To
, a value of type From
may be converted to a value of type To
if all the types in the type set of From's constraint can be converted to all the types in the type set of To's constraint.
In this case you don't really have a From
because it is the slice index int
; the destination type would be T
(even though this is probably not what you want, see below why). Of course int
can be converted to T
's type set due to it including only numerical types (albeit with truncation or loss of precision in case of int8
or float64
!)
indexs = append(indexs, T(i))
however your program is declaring the slice of indices as []T
, which means that instantiating your generic function as:
is := FindIndexValue([]float64{1,5,7,9}, float64(9))
will yield a result of type []float64
. Since the returned values are slice indices, which are always int
, this doesn't make a lot of sense.
Better would be to return simply []int
:
func FindIndexValue[T Number](array []T, value T) []int {
var indices []int
for i := range array {
// match on the generically typed slice item
if array[i] == value {
// store slice indices as ints
indices = append(indexs, i)
}
}
return indices
}
Playground: https://gotipplay.golang.org/p/EykXppG2qJa
答案2
得分: 5
索引始终是整数类型(int
),无论切片的元素类型如何。因此,结果类型应该是[]int
。
为什么你希望它是[]T
呢?如果T
是uint8
,并且传入的切片包含超过256个元素,你甚至无法返回正确的索引。
func FindIndexValue[T types.Number](array []T, value T) []int {
var indices []int
for i, v := range array {
if v == value {
indices = append(indices, i)
}
}
return indices
}
英文:
The index is always integer type (int
) regardless of the element type of the slice. So result type should be []int
.
Why would you want it to be []T
? If T
is uint8
and the passed slice contains more than 256 elements, you couldn't even return the proper indices.
func FindIndexValue[T types.Number](array []T, value T) []int {
var indices []int
for i, v := range array {
if v == value {
indices = append(indices, i)
}
}
return indices
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论