一些编程语言如C++、Rust都是支持泛型特例化的,Go泛型支持吗?
所谓特例化(specialization)对泛型功能代码的扩展。比如对于泛型的函数,它的实现对于满足泛型参数的所有类型(type set)都是一样的,如果我们想对这些类型集(type set)中的一个,它的函数做特殊的实现,一些支持泛型特例化的语言是可以支持的,比如C++ template:
1 2 3 4 5 6 7 8 9 10 11
| template <typename T> void fun(T a) { cout << "template fun(): " << a << endl; } template <> void fun(int a) { cout << "specialized template fun for int type: " << a << endl; }
|
这里fun
是一个函数模板,但是针对int
类型,此函数有特殊的实现。
Rust也有类似的功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #![feature(min_specialization)] struct Special { x : usize, y : usize } trait MyTrait { fn myfunc(&self); } impl<T> MyTrait for T { default fn myfunc(&self) { println!("hi"); } } impl MyTrait for Special { fn myfunc(&self) { println!("I'm special"); } } fn main() { let spe = Special{ x: 1, y: 2, }; spe.myfunc(); }
|
这里MyTrait
针对通用类型T
有一个默认实现,但是针对特定的类型Special
,有一个特定的实现。
其它编程语言当前还不支持特例化,但是可以通过方法重载实现类似的功能,如typescript、C#等。
另外复杂的特例化还包括部分特例化的特性。
那么问题来了,Go的泛型(类型参数)是否支持特例化呢?我们先写个例子:
1 2 3 4 5 6 7 8 9 10 11 12
| type List[T any] struct { next *List[T] value T } func (l *List[T]) Len() int { return 0 } func (l *List[string]) Length() int { return 0 }
|
这里我们定义了一个泛型类型List[T any]
, 包括它的一个泛型方法Len() int
,接下来我们尝试定义一个“特例化”的方法Length() int
。
编译一下,没问题,程序可以正常编译,难道Go泛型真的支持特例化吗?
我们再增加一个特例化泛型方法试试:
1 2 3
| func (l *List[int]) Size() int { return 0 }
|
这个时候再编译试试,编译出错:
1
| cannot use 0 (untyped int constant) as int value in return statement
|
其实这个错误信息已经告诉我们了,这里的int
并不是内建的整数类型,而是一个类型参数的名称,等价于我们常用的T
、K
、V
。这里我们使用int
作为类型参数的名称很有迷惑性。
所以答案也是很明确的,当前Go 1.18并不支持泛型特例化, 小心别掉到坑里了。