Can I create an alias for a generic function? I get error "Cannot use generic function without instantiation"

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

Can I create an alias for a generic function? I get error "Cannot use generic function without instantiation"

问题

我可以定义一个通用函数:

package hello

func IsZero[T int64|float64](value T) bool {
   return value == 0
}

然后,如果我尝试在另一个包中给该函数取一个别名,会失败:

package world

import "hello"

var IsZero = hello.IsZero

上述代码无法编译通过:

无法使用未实例化的通用函数 hello.IsZero

相反,下面的代码可以正常工作:

var IsZero = hello.IsZero[int64]

是否有可能使用其他语法来实现这个功能?

英文:

I can define a generic function:

package hello

func IsZero[T int64|float64](value T) bool {
   return value == 0
}

Then if I try to alias that function in another package, it fails:

package world

import "hello"

var IsZero = hello.IsZero

The above doesn't compile with:

> cannot use generic function hello.IsZero without instantiation

Instead this works:

var IsZero = hello.IsZero[int64]

Is it possible to do this, using some other syntax?

答案1

得分: 4

这不是一个别名。实际上,你已经得到了答案。但是如果你想要一个正式的参考,可以从语言规范的Instantiations部分查看:

一个未被调用的泛型函数需要一个类型参数列表来进行实例化。

因此,当你尝试初始化一个函数类型的变量时,函数hello.IsZero不会被调用,因此需要使用具体的类型参数进行实例化:

// 未被调用,使用int64进行实例化
var IsZero = hello.IsZero[int64]

此时,变量(为了清晰起见,我们给它取一个不同的名字)zeroFunc具有一个具体的函数类型:

var zeroFunc = IsZero[int64]
fmt.Printf("type: %T\n", zeroFunc)

输出结果为:

type: func(int64) bool

这可能是你想要的,因为这实际上是将函数单态化。如果你只想要一个具有相同实现(或稍作修改)的局部符号,声明一个“包装”函数即可。只需记住,你的包装函数的类型参数只能比被包装函数的类型参数更严格相同

例如,给定以下函数:

IsZero[T int64 | float64](v T)

你的包装函数不能是:

WrapIsZeroPermissive[T int64 | float64 | complex128](v T) bool {
    return IsZero(v) // 无法编译通过,T的类型集是一个超集
}

但是可以是:

WrapIsZeroStricter[T int64](v T) bool {
    return IsZero(v) // 可以,T的类型集是一个子集
}
英文:

That's not an alias. And you already have your answer, actually. But if you want a formal reference, from the language specs, Instantiations:

> A generic function that is is not called requires a type argument list for instantiation

So when you attempt to initialize a variable of function type, the function hello.IsZero is not called, and therefore requires instantiation with specific type parameters:

// not called, instantiated with int64
var IsZero = hello.IsZero[int64]

At this point the variable (let's give it a different name for clarity) zeroFunc has a concrete function type:

	var zeroFunc = IsZero[int64]
	fmt.Printf("type: %T\n", zeroFunc) 

Prints:

type: func(int64) bool

This might or might not be what you want, as this effectively monomorphises the function.

If you just want to have a local symbol, with the same implementation (or a tweaked version thereof), declaring a "wrapper" function works. Just remember that the type parameters of your wrapper can only be as strict or stricter than the wrapped one's

E.g. Given

IsZero[T int64 | float64](v T)

your wrapper can not be

WrapIsZeroPermissive[T int64 | float64 | complex128](v T) bool {
    return IsZero(v) // does not compile, T's type set is a superset
}

but can be

WrapIsZeroStricter[T int64](v T) bool {
    return IsZero(v) // ok, T's type set is a subset
}

答案2

得分: 0

如果函数很小,就像在问题中一样,最简单的方法可能是直接将其作为供应商提供:

package vendor

func thisIsJustCopy[T int64|float64](value T) bool {
   return value == 0
}

但是如果函数很大,可以这样做:

package world
import "hello"

func IsZero[T int64|float64](value T) bool {
   return hello.IsZero(value)
}
英文:

If the function is small, like in the question, it's probably easier to just vendor it:

package vendor

func thisIsJustCopy[T int64|float64](value T) bool {
   return value == 0
}

but if the function is big, you can do it like this:

package world
import "hello"

func IsZero[T int64|float64](value T) bool {
   return hello.IsZero(value)
}

答案3

得分: -2

你可以尝试在另一个包中使用别名来引用该函数。

别名只适用于类型,你的代码只是尝试声明一个变量。

是否可以使用其他语法来实现这个目的?

不可以。

英文:

> I try to alias that function in another package

Aliases work for types only. Your code just tries to declare a variable.

> Is it possible to do this, using some other syntax?

No.

huangapple
  • 本文由 发表于 2022年3月19日 00:05:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/71529940.html
匿名

发表评论

匿名网友

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

确定