如何在Go泛型中指定数组作为类型约束?

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

How to specify array as type constraints in Go generics?

问题

在重写泛型代码以减少代码重复时,有一种类型期望[N]T作为类型约束。

在Go语言中是否可以指定数组作为类型约束?
例如,[32768]byte[100]uint64

如果我的函数必须处理多种不同长度的数组类型,该怎么办?

英文:

During rewriting code in generics to reduce code duplication, there is one type that expect a [N]T as type constraints.

Is it possible to specify array as type constraints in Go?
eg, [32768]byte or [100]uint64.

What if my function has to handle several array types with different lengths?

答案1

得分: 1

你可以在类型参数约束中使用数组,但必须指定长度:

func foo[T ~[2]uint64](v T) {}

当然,这不会接受 type Foo [3]uint64 作为类型参数,因为长度不同。就像声明数组变量时不允许非常量长度一样。

因此,以下代码也是有效的:

const length = 2

type C interface {
	~[length]uint64
}

[...]uint64{} 这种表示方式只能在复合字面量中使用,所以在约束中不可选。

这也意味着为了在同一个约束中指定多个数组类型,你必须使用联合项:

type C interface {
	~[100]byte | ~[2]uint64 | ~[3]uint64
}

如果你的函数需要接受许多可能的数组类型,这样做可能不太实用。根据你的实际用例,接受切片可能更值得考虑:

type C2 interface {
	~[]byte | ~[]uint64
}

然后可以这样使用:

func foo[T C2](v T) { ... }
// 或者使用无名约束
func foo[T ~[]byte | ~[]uint64](v T) { ... }

// 使用示例
func main() {
    twoArr := [2]uint64{10,20}
    foo(twoArr[:])

    threeArr := [3]uint64{10,20,30}
    foo(threeArr[:])
}
英文:

You can use arrays in type parameter constraints but you must specify the length:

func foo[T ~[2]uint64]MyFunc(v T) {}

This of course will not admit, say, type Foo [3]uint64 as type argument, because the lengths differ. Just like declaring array variables doesn't admit non-const length.

So this also works:

const length = 2

type C interface {
	~[length]uint64
}

The notation [...]uint64{} is available only in composite literals, so that's not an option in constraints either.

This also implies that in order to specify more than one array type in the same constraint, you have to use a union term:

type C interface {
	~[100]byte | ~[2]uint64 | ~[3]uint64
}

And yes, this is impractical if you have many possible array types that your function is supposed to accept. Depending on your actual use case, it might be worth to accept slices instead.

type C2 interface {
	~[]byte | ~[]uint64
}

and use it as:

func foo[T C2](v T) { ... }
// or with unnamed constraint
func foo[T ~[]byte | ~[]uint64](v T) { ... }

// usage
func main() {
    twoArr := [2]uint64{10,20}
    foo(twoArr[:])

    threeArr := [3]uint64{10,20,30}
    foo(threeArr[:])
}

huangapple
  • 本文由 发表于 2023年1月28日 13:35:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75265612.html
匿名

发表评论

匿名网友

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

确定