Go泛型:为零参数的变元函数推断类型参数



假设我有一个函数,它有两个通用参数,其中一个是可变参数:

func Constructor[F any, Opt any](f F, opts ...Opt) {}

如果我传入几个选项,调用这个函数可以很好地工作:

Constructor(func() *myService { return ... }, 1, 2, 3)

但是,在没有任何Opts的情况下调用它失败:

Construtor(func() *myService { return ... })

编译器抱怨:

不能将'func((*myService'(type func(*myService((用作类型(F,Opt(或F

我认为这是因为编译器在这种情况下无法计算出Opt的类型。

虽然这是有道理的,但也很烦人。编译器不需要Opt的类型,因为它是空的。

解决此问题的一种方法是定义两个函数ConstructorConstructorWithOpts。如果只有一个函数,那就太好了。有什么想法吗?

编译器不需要Opt类型,因为它是空的。

即使调用方决定提供零参数,函数体仍然可以使用变参数的值进行操作。所以编译器肯定需要Opt的类型。

此外,类型推理的规则是明确的:

类型推断基于

  • 类型参数列表
  • 用已知的键入参数(如果有(
  • 普通函数的列表(可能为空(自变量(仅在函数调用的情况下(

当某个类型参数的参数为零时,上述第三个选项不适用。如果FOpt完全不相关,则第二个选项也不适用。

作为推论,如果调用方需要声明Constructor函数类型的,则考虑调用方必须提供所有类型参数:

ctor := Constructor[func(), any] // not called!
ctor(f, 1, 2, 3)

最干净的方法显然是让编译器推断F并显式指定Opts,尽管这需要反转函数声明中类型参数的顺序,这样客户端就可以提供第一个,而省略第二个。您可以定义一个any类型来提高可读性:

func Constructor[Opt any, F any](f F, opts ...Opt) {}
type NoOpts any // just for better readability
func main() {
f := func() *myService { return ... }
// NoOpts instantiates Opt; F inferred
Constructor[NoOpts](f)
}

否则,只需使Constructor不可变:

func Constructor[F any](f F) {
ConstructorWithOpts[F, any](f)
}
func ConstructorWithOpts[F any, Opt any](f F, opts ...Opt) {
// ...
}

您可以为可变参数提供一个空切片:

Constructor(func() *myService { return nil }, []int{}...)

您也可以通过nil,但它更详细:

Constructor(func() *myService { return nil }, ([]int)(nil)...)

或者提供类型参数的值:

Constructor[func() *myService, any](func() *myService { return nil })

在围棋场上试试这些。

最新更新