通用方法是否可以只与类型化泛型的子集一起使用?

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

Is it possible for generic methods to only work with a subset of the typed generic?

问题

我有一个结构体,我希望能够处理任何类型的数字,但其中一些方法只能处理浮点数(这是期望的)。有没有办法将方法的类型限定为只能处理浮点数?

假设我有以下代码:

type Number interface {
    Integer | Float
}

type Integer interface {
    uint | uint8 | uint16 | uint32 | uint64 | int | int8 | int32 | int64
}

type Float interface {
    float32 | float64
}

我定义了一个结构体:

type MyStruct[T Number] struct {
    Data []T
}

我想要一个只能处理浮点数的方法:

func (ms MyStruct[T]) SomeMethod() MyStruct[T] {
    result := ms.Clone()
    for i, v := range result.Data {
        result.Data[i] = helper[Float](v)
    }
    return result
}

func helper[T Float] (v T) T {
    return v*v
}

我希望SomeMethod只在"T"是"Float"类型的泛型时才能使用。在Go语言中,泛型是否支持这样的功能呢?

或者更正式一些,假设MyStruct的实例化类型是MyStruct[Float32]{}MyStruct[float64]{},允许调用者调用SomeMethod,否则会给出类型错误。

我也可以接受其他方法来实现这个目标,但这是我希望实现的方式。我正在编写一个张量库,我需要同时支持整数和浮点数,并且希望某些方法只能处理浮点数。虽然我可以让它处理整数,但这并没有太多意义。我更希望用户在尝试使用某些方法处理整数时得到错误提示,以避免出错。

英文:

I have a struct that I want to work with any type of number, but some of the methods will only work with floats (this is desired). Is there any way to type a method to only work with floats?

Let's say I have something like:

type Number interface {
    Integer | Float
}

type Integer interface {
    uint | uint8 | uint16 | uint32 | uint64 | int | int8 | int32 | int64
}

type Float interface {
    float32 | float64
}

I have a struct defined as:

type MyStruct[T Number] struct {
    Data []T
}

I want a method that only works for floats:

func (ms MyStruct[T]) SomeMethod() MyStruct[T] {
    result := ms.Clone()
    for i, v := range result.Data {
        result.Data[i] = helper[Float](v)
    }
    return result
}

func helper[T Float] (v T) T {
    return v*v
}

I want SomeMethod to only work if "T" is a "Float" type generic. Is this possible with generics in Go?

Or something more formal like, given that type MyStruct is instantiated with MyStruct[Float32]{} or MyStruct[float64]{}, allow caller to call "SomeMethod", otherwise, give a type error.

I am open to other ways of doing this as well, but this what I wish to do. I am writing a tensor library. I need both ints and floats, and some methods to work with just floats. I could make it work with ints, but it doesn't really make sense. I'd rather the user get an error if they try to use certain methods with ints to stray them away from it.

答案1

得分: 2

不,这是不可能的。这不是泛型的工作方式。

英文:

No, this is not possible. That’s not how generics work.

答案2

得分: 0

不,使用与结构体定义相同类型参数的方法。您不能对它们进行特殊化、添加或删除类型参数等操作。

您可以将方法编写为简单的函数,将结构体作为参数传递。然后,使用实例化为Integer的结构体调用将无法编译。

// 不是方法,将结构体作为参数
func SomeMethod[T Float](ms MyStruct[T]) MyStruct[T] {
}

func main() {
	m1 := MyStruct[float64]{}
    // 编译通过
	SomeMethod(m1)            

	m2 := MyStruct[uint8]{}
    // 无法编译
	SomeMethod(m2)            
}

区别在于泛型函数在调用点(在此示例中)实例化,并且您可以在每次调用时提供不同的T,而方法与类型一起实例化。

另一种方法是检查T的具体类型,如果它不是所需类型之一,则引发 panic 或返回错误,但这违反了最小惊讶原则:如果您定义了MyStruct[T Number],则预期其方法在Number中的所有类型上都能正常工作。

英文:

No, methods run with the same type parameter the struct is defined with. You can't specialize them, add or remove type parameters, etc.

What you can do is to write the method as a simple function instead with the struct as an argument. Then calls with structs instantiated with Integer would simply not compile.

// not a method, takes the struct as argument
func SomeMethod[T Float](ms MyStruct[T]) MyStruct[T] {
}

func main() {
	m1 := MyStruct[float64]{}
    // compiles
	SomeMethod(m1)            

	m2 := MyStruct[uint8]{}
    // doesn't compile
	SomeMethod(m2)            
}

The difference is that the generic function is instantiated at the call site (in this example) and you can supply different T's at each call, whereas the method is instantiated together with the type.

An alternative would be to inspect the concrete type of T and panic or return error if it's not one of the desired types, but this violates the principle of least surprise: if you define MyStruct[T Number] it is expected that its methods work the same with all types in Number.

huangapple
  • 本文由 发表于 2023年6月17日 01:27:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76492419.html
匿名

发表评论

匿名网友

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

确定