一、函数定义中的泛型
如下图:
是一个函数的泛型示例。这可以理解为:
函数largest有泛型类型T,它有一个参数list,它是一个T值的slice,且largest函数会返回一个与T相同类型的值。
下面是函数的运用,可以看到,函数名后面我们可以传入不同的参数类型。
但值得注意的是,不是所有的类型都可以进行函数原型里的">"比较操作,除非你实现特殊类型的比较trait。即实现一般面向对象语言里的运算符重载。
二、结构体定义中的泛型
同样也可以使用 <> 语法来定义拥有一个或多个泛型参数类型字段的结构体。
如下所示,在结构体名字Point后面加上泛型语法:
可以看到两个变量的类型如下:
改成多个泛型参数:
如上图所示,有T和U两个泛型参数,这样Point实例中,也就可以用不同类型做初始化了。
三、枚举定义中的泛型
枚举中使用泛型,就可以让枚举的变体拥有泛型数据类型。
例如Option<T>和Result<T, E>。
Option<T>这个枚举表示某个值可能存在也可能不存在的一种不确定性抽象概念,又叫“可空变量”。正是因为Option枚举实现了泛型,所以不管这个可能存在的值是什么类型的,我们都可以用Option<T>来表示。
Result<T, E>这个枚举表示包含错误信息的结果,它包含了两种可能的结果:Ok(T)即结果为成员T,Err(E)即结果为错误成员E。因此Result枚举类型使用到了多个泛型类型参数。
四、方法定义中的泛型
为struct或enum实现方法的时候,可以在定义中使用泛型。
从示例可以看出,我们为Point<T>结构体实现了一个方法,方法名为x,值得注意的是,我们需要在impl后面加上<T>,这样写就表明,impl实现的泛型针对的是泛型T,而不是只给某种特定类型实现方法。
只给某种类型实现方法,语法如下:
这里的x方法,只有Point<i32>类型才可以使用。
可以看出,如果我们在实现方法泛型的时候,如果不在impl后面加<T>,就会出现歧义:后面Point<T>是具体类型还是泛型?毕竟我们是可以自己定义一个T类型的,定义完后Point<T>就是一个具体的类型了。
另外:
结构体中的泛型类型参数可以和方法中的泛型类型参数不同。
例子如下:
可以看到Point<T, E>结构体有两个泛型参数,impl为带泛型参数的结构体实现方法。
方法mixup有<V, W>两个泛型参数,它实现的功能其实就是返回Point结构体中的T类型的x值和W类型的y值。
当我们在main函数中调用的时候:
可以看出:
T类型的x值:5
W类型的y值:'c'
经过编译运行后,得出的结果与我们想要的一致。
五、泛型代码的性能
rust在执行编译的时候,会进行泛型代码的单态化(monomorphization),简单来说,就是编译阶段编译器会把泛型参数T、E...等等全部用具体的类型替换掉。
因此,rust实现泛型的方式决定了使用泛型的代码和使用具体类型的代码运行速度是一样的。