英文:
How to constrain type to types with index?
问题
我决定深入学习Go语言,因为1.18版本引入了泛型。我想实现一个只接受顺序类型(数组、切片、映射、字符串)的算法,但我不知道如何实现。
是否有一种可以通过索引访问的方法可以解决这个问题?
英文:
I decided to dive into Go since 1.18 introduced generics. I want to implement an algorithm that only accepts sequential types — arrays, slice, maps, strings, but I'm not able to crack how.
Is there a method that can be targeted involving indexability?
答案1
得分: 5
你可以在联合类型中使用约束,但是唯一有意义的约束是:
type Indexable interface {
~[]byte | ~string
}
func GetAt[T Indexable](v T, i int) byte {
return v[i]
}
就目前而言,就是这样。为什么呢?
-
在具有联合约束的类型上允许的操作仅限于约束类型集中的所有类型允许的操作。
-
要允许索引,联合中的类型必须具有相等的键类型和相等的元素类型。
-
类型参数提案建议可以将
map[int]T
与[]T
联合使用,但是这已被禁止。规范现在在索引表达式中提到了这一点:“如果P的类型集中有一个映射类型,则该类型集中的所有类型必须是映射类型,并且相应的键类型必须全部相同”。 -
对于数组,长度是类型的一部分,因此联合类型必须指定您想要处理的所有可能长度,例如
[1]T | [2]T
等。这非常不实用,并且容易出现越界问题(有一个提案来改进这个问题)。
因此,唯一支持索引的具有不同类型的联合类型似乎是[]byte | string
(可能近似为~
)。由于byte
是uint8
的别名,您也可以使用[]uint8
进行实例化。
除此之外,没有其他方法可以定义一个支持在所有可能的可索引类型上进行索引的约束。
请注意,[]byte | string
支持索引但不支持范围,因为这个联合类型没有核心类型。
Playground: https://gotipplay.golang.org/p/uatvtMo_mrZ
英文:
You can use a constraint with a union, however the only meaningful one you can have is:
type Indexable interface {
~[]byte | ~string
}
func GetAt[T Indexable](v T, i int) byte {
return v[i]
}
And that's all, for the time being. Why?
-
The operations allowed on types with union constraint are only those allowed for all types in the constraint type set.
-
To allow indexing, the types in the union must have equal key type and equal element type.
-
The type parameter proposal suggests that
map[int]T
could be used in a union with[]T
, however this has been disallowed. The specs now mention this in Index expressions: "If there is a map type in the type set of P, all types in that type set must be map types, and the respective key types must be all identical". -
For arrays, the length is part of the type, so a union would have to specify all possible lengths you want to handle, e.g.
[1]T | [2]T
etc. Quite impractical, and prone to out-of-bounds issues (There's a proposal to improve this).
So the only union with diverse types that supports indexing appears to be []byte | string
(possibly approximated ~
). Since byte
is an alias of uint8
, you can also instantiate with []uint8
.
Other than that, there's no other way to define a constraint that supports indexing on all possible indexable types.
NOTE that []byte | string
supports indexing but not range, because this union doesn't have a core type.
Playground: https://gotipplay.golang.org/p/uatvtMo_mrZ
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论