也来谈谈golang泛型
文章目录
也来谈谈golang泛型
我们都知道golang在1.18版本之后引入了泛型,这对广大因不支持泛型饱受重复代码之苦的gophers喜大普奔。笔者在最近一个项目中尝鲜了泛型特性。总的来说,1.18中引入泛型相比之前版本是一个巨大的进步,但同时也应当看到,golang泛型的表达能力相比c++/rust等语言还是有不小的差距,这种差距也大大影响了golang泛型的表达能力。本文将简要介绍golang泛型的使用和一些目前尚不支持的功能。
泛型使用
闲话少说,看代码就明白了:
/// 定义类型合约Addable
/// 只能是int或string类型或它们的alias类型(如type Name string)
type Addable interface {
~int | ~string
}
// myAdd函数的参数类型必须满足合约Addble
func myAdd[T Addable](a, b T) T {
return a + b
}
func main() {
var (
ia int = 1
ib int = 2
)
/// 编译器自动推导参数类型T = int
fmt.Println(myAdd(ia, ib)) // 输出3
type Name string
var (
sa Name = "hello"
sb Name = " world"
)
/// 编译器自动推导参数类型T = Name = ~string
fmt.Println(myAdd(sa, sb)) // 输出hello world
}
除了支持函数泛型之外,golang还支持interface和struct的泛型化,对标c++的模板类。
好了,golang泛型的使用介绍到此为止了。接下来咱就要列举golang泛型的"两宗罪"了。相信未来go社区会很快补齐这些短板,不断增强泛型的表达能力。
不支持泛型特化
泛型特化在c++中是及其常规的操作。正是因为有了泛型特化,c++才能实现如此多的Traits特性。一旦使用了泛型,某个函数或类针对每一个具体类型都要有对应的实现,具体类型之间既有共性(它们都满足某个类型合约)又有差异性(例如int和[]byte的相加实现不相同)。为了解决这种差异性,c++中支持了泛型特化,而这正是go泛型所欠缺的。
cpp支持的泛型特化
#include <iostream>
#include <cstring>
/// C++20中引入了concept可实现对于golang type contract相同的效果
/// 这里为了简化问题未使用concept
template <class T>
T myAdd(T a, T b)
{
return a+b;
}
/// 针对char *类型的特化
template <>
char * myAdd(char * a, char *b)
{
return strncat(a, b, strlen(b));
}
int main()
{
std::cout << myAdd(1, 2) << std::endl; // 输出3
char a[16] = "hello";
char b[16] = " world";
std::cout << myAdd(a, b) << std::endl; // 输出hello world
return 0;
}
golang不支持的泛型特化
/// 合约新增一种类型: []byte
type Addable interface {
~int | ~string | []byte
}
/// 针对[]byte的特化实现
func myAdd[T []byte](a, b T) {
a = append(a, b...)
return a
}
func myAdd[T Addable](a, b T) T {
return a + b
}
/* 编译报错
./main.go:16:6: myAdd redeclared in this block
./main.go:11:6: other declaration of myAdd
./main.go:17:9: invalid operation: operator + not defined on a (variable of type T constrained by Addable)
*/
不支持类方法使用泛型
c++支持类的方法使用泛型
class A
{
public:
template <class T>
T add(T a, T b)
{
return a+b;
}
};
int main()
{
int a = 1, b = 2;
A o;
std::cout << o.add(a, b) << std::endl;
}
golang不支持类的方法使用泛型
type Addable interface {
~int | ~string
}
type A struct{
}
func (a *A) Add[T Addable](a, b T) T{
return a+b
}
func main()
{
o := A{};
var (
a int = 1
b int = 2
)
o.Add(a, b)
}
/*
编译报错:
./main.go:12:16: syntax error: method must have no type parameters
./main.go:17:1: syntax error: unexpected semicolon or newline before {
./main.go:23:2: syntax error: non-declaration statement outside function body
*/
总结
本文简要介绍了golang泛型如何使用,然后将其与c++模板对比,指出golang泛型亟待补足的两块短板。
参考
文章作者 后端侠
上次更新 2022-09-12