go - 约束满足 3 个约束数组。使用方法 float

标签 go generics

对于 Go 1.18 的泛型,我一直期待的一件事是使用 3 元素向量类型,它可以采用 float32float64 作为它的元素。今天来吧,这现在成为可能:

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

这看起来很冗长。 TA 真的有必要同时定义吗?

当我们要求实现 AddMul 时,情况会变得更糟:

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

一个额外的类型,三个泛型类型参数,并且必须给 ab 单独的类型。更进一步,我看不到让表达式 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)也是如此,因为您希望同时捕获 TA,但同样,在调用站点,它会变得更好:

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/

相关文章:

Go 方法参数和 float64 数组给出意外错误

node.js - 如何在产品环境中保护我的 GO REST 服务?

java - 使用泛型并尝试摆脱不安全操作警告

java - Java SE 7 中不可具体化类型的可变参数——怎么样?

java - public<T> void run (T object ) { } 是什么意思?

reactjs - 如何确定字符串是否是 Typescript 中的 keyof 接口(interface)?

image - 如何获取 image.RGBA 或任何其他类型中特定像素的几何形状?

windows - 如何将 uintptr 转换为 go struct

go - 将结构转换为基类

java - 使用反射方法检索类的通用参数是否保证有效(在我的例子中)?