如何将类型限制为具有索引的类型?

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

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]
}

就目前而言,就是这样。为什么呢?

  1. 在具有联合约束的类型上允许的操作仅限于约束类型集中的所有类型允许的操作。

  2. 要允许索引,联合中的类型必须具有相等的键类型和相等的元素类型。

  3. 类型参数提案建议可以将map[int]T[]T联合使用,但是这已被禁止。规范现在在索引表达式中提到了这一点:“如果P的类型集中有一个映射类型,则该类型集中的所有类型必须是映射类型,并且相应的键类型必须全部相同”。

  4. 对于数组,长度是类型的一部分,因此联合类型必须指定您想要处理的所有可能长度,例如[1]T | [2]T等。这非常不实用,并且容易出现越界问题(有一个提案来改进这个问题)。

因此,唯一支持索引的具有不同类型的联合类型似乎是[]byte | string(可能近似为~)。由于byteuint8的别名,您也可以使用[]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?

  1. The operations allowed on types with union constraint are only those allowed for all types in the constraint type set.

  2. To allow indexing, the types in the union must have equal key type and equal element type.

  3. 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".

  4. 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

huangapple
  • 本文由 发表于 2022年2月21日 05:22:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/71198899.html
匿名

发表评论

匿名网友

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

确定