对于 Go 1.18 的泛型,我一直期待的一件事是使用 3 元素向量类型,它可以采用 float32
或 float64
作为它的元素。今天来吧,这现在成为可能:
import "golang.org/x/exp/constraints"
type Vec3[T constraints.Float] [3]T
func (vec Vec3[T]) Add(other Vec3[T]) Vec3[T] {
return Vec3[T]{vec[0] + other[0], vec[1] + other[1], vec[2] + other[2]}
}
func (vec Vec3[T]) Mul(factor T) Vec3[T] {
return Vec3[T]{vec[0] * factor, vec[1] * factor, vec[2] * factor}
}
然后我想知道,相应的约束会是什么样子?省略方法,我得出以下解决方案:
type Vec3ish[T constraints.Float] interface {
~[3]T
}
接受相应参数的函数可能如下所示:
func addVecs[A Vec3ish[T], T constraints.Float](a, b A) A {
return A{a[0] + b[0], a[1] + b[1], a[2] + b[2]}
}
这看起来很冗长。 T
和 A
真的有必要同时定义吗?
当我们要求实现 Add
和 Mul
时,情况会变得更糟:
type Vec3ish[T constraints.Float] interface {
~[3]T
}
type Vec3ishUseful[T constraints.Float, A Vec3ish[T]] interface {
Vec3ish[T]
Add(A) A
Mul(T) A
}
func addVecsGeneric[U Vec3ishUseful[T, A], A Vec3ish[T], T constraints.Float](a U, b A) A {
return a.Add(b)
}
一个额外的类型,三个泛型类型参数,并且必须给 a
和 b
单独的类型。更进一步,我看不到让表达式 a.Add(b).Add(b.Add(a))
在函数内工作的方法。这不是我所希望的 future 。这里需要发生什么?
最佳答案
This seems verbose. Is it really necessary to define both T and A?
是的,是的。
你的接口(interface) Vec3ish[T constraints.Float]
本身是参数化的,所以你必须在将它用作约束时实例化它。给定类型约束 A Vec3ish[T]
,您可以看到使用它的函数也在 T
中进行了参数化,并且一个 T
满足Vec3ish
中的约束在编译时。
函数声明可能看起来有些冗长,但在调用点它不会,因为类型推断会完成所有的工作:
v1 := Vec3[float64]{1, 2, 3}
v2 := Vec3[float64]{5, 6, 7}
result := addVecs(v1, v2)
稍微不那么冗长的是使用 vector 约束的简写,但如果您计划重用 Vec3ish
约束,命名接口(interface)可能会更好:
func addVecs[A ~[3]T, T constraints.Float](a, b A) A {
return A{a[0] + b[0], a[1] + b[1], a[2] + b[2]}
}
其他接口(interface)也是如此,因为您希望同时捕获 T
和 A
,但同样,在调用站点,它会变得更好:
addVecsGeneric(v1, v2)
人们可能会考虑使用参数化接口(interface)作为参数的类型,然后让类型推断完成剩下的工作:
type Vec3ishUseful[T constraints.Float, A Vec3ish[T]] interface {
Add(A) A
Mul(T) A
}
// Instantiating Vec3ishUseful with type params T and A
func addVecsGeneric[A Vec3ish[T], T constraints.Float](a Vec3ishUseful[T, A], b A) A {
return a.Add(b)
}
// addVecsGeneric(v1, v2) doesn't compile
但是这不起作用(还?)。关于这个 here 有相当广泛的讨论.因此,通过这条路线,您必须放弃推理并显式传递类型参数。这在某种程度上分散了函数签名和调用者之间的冗长:
addVecsGeneric[Vec3[float64], float64](v1, v2)
关于go - 约束满足 3 个约束数组。使用方法 float ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71490519/