英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论