泛型
泛型主要解决如何将类型和功能推广到更广泛场景的问题。
例如,定义一个名为 foo
的泛型函数,它接受任何类型的参数 T
:
fn foo<T>(arg: T) { ... }
函数
struct A; // 具体类型 `A`。
struct SGen<T>(T); // 泛型类型 `SGen`。
// 定义一个函数 `gen_spec_t`,它接受类型为 `SGen<T>` 的参数 `_s`。
// 它已经明确给出了自定义的具体类型参数 `A`,`A` 不是泛型类型参数,因此它不是泛型的。
fn gen_spec_t(_s: SGen<A>) {}
// 定义一个函数 `gen_spec_i32`,它接受类型为 `SGen<i32>` 的参数 `_s`。
// 它已经明确给出了类型参数 `i32`,这是一个具体类型。
// 因为 `i32` 不是一个泛型类型,所以这个函数也不是泛型的。
fn gen_spec_i32(_s: SGen<i32>) {}
// 定义一个函数 `generic`,它接受类型为 `SGen<T>` 的参数 `_s`。
// 因为 `SGen<T>` 前面带有 `<T>`,所以这个函数对 `T` 泛型。
fn generic<T>(_s: SGen<T>) {}
fn main() {
// 使用非泛型函数
gen_spec_t(SGen(A)); // 隐式指定类型参数 `A`。
gen_spec_i32(SGen(6)); // 隐式指定类型参数 `i32`。
// 显式指定类型参数 `char` 给 `generic()`。
generic::<char>(SGen('a'));
// 隐式指定类型参数 `char` 给 `generic()`。
generic(SGen('c'));
}
实现
struct S<T> {
v: T,
}
impl<T> S<T> {
fn value(&self) -> &T {
&self.v
}
}
fn main() {
let a = S { v: 58i32 };
println!("{}", a.value());
}
特征
traits
也可以是泛型的。
// 用泛型类型参数 `T` 定义一个名为 `Printable` 的泛型特征
trait Printable<T> {
// 用于获取自身引用并返回类型为 `T` 的值的方法 `print`
fn print(&self) -> T;
}
// 为 `i32` 类型实现 `Printable` 特征
impl Printable<String> for i32 {
// 为 `print` 方法实现将整数转换为字符串的逻辑
fn print(&self) -> String {
self.to_string()
}
}
// 为 `bool` 类型实现 `Printable` 特征
impl Printable<&'static str> for bool {
// 为 `print` 方法实现返回 "true" 或 "false" 的字符串切片的逻辑
fn print(&self) -> &'static str {
if *self {
"true"
} else {
"false"
}
}
}
fn main() {
let number = 58;
let number_str = number.print();
println!("Printed number: {}", number_str);
let boolean = true;
let boolean_str = boolean.print();
println!("Printed boolean: {}", boolean_str);
}
Bounds (限定)
在使用泛型时,类型参数通常需使用特征作为限定,以规定类型实现的功能。
例如,以下示例使用特征 Display
打印,因此它要求 T
被限制为 Display
;也就是说,T
必须实现 Display
。
fn printer<T: Display>(t: T) {
println!("{}", t);
}
多重限定
可以使用 +
对单个类型应用多个限定。
// 定义一个名为 `Printable` 的特征
trait Printable {
fn print(&self);
}
// 定义一个名为 `Debuggable` 的特征
trait Debuggable {
fn debug(&self);
}
// 一个泛型函数,接受实现 `Printable` 和 `Debuggable` 特征的参数
fn print_and_debug<T: Printable + Debuggable>(item: T) {
item.print();
item.debug();
}
Where 子句
可以使用 where
子句在左花括号 {
之前表达限定。此外,where
子句可以将限定应用于任意类型,而不仅仅是输入参数的类型。
impl <A: TraitB + TraitC, D: TraitE + TraitF> MyTrait<A, D> for YourType {}
// Expressing bounds with a `where` clause
impl <A, D> MyTrait<A, D> for YourType where
A: TraitB + TraitC,
D: TraitE + TraitF {}
使用 "where 子句",前面 print_and_debug 的示例可以转换为这样:
trait Printable {
fn print(&self);
}
trait Debuggable {
fn debug(&self);
}
fn print_and_debug<T>(item: T)
where
T: Printable + Debuggable,
{
item.print();
item.debug();
}
struct Data;
impl Printable for Data {
fn print(&self) {
println!("Printing");
}
}
impl Debuggable for Data {
fn debug(&self) {
println!("Debugging");
}
}
fn main() {
let data = Data;
print_and_debug(data);
}
关联类型
关联类型 是对 trait
泛型的扩展,它允许 trait
在内部定义新项。
// 定义一个名为 `Container` 的特征,并带有关联类型 `Item`
trait Container {
type Item;
// 返回关联类型的实例的方法
fn first(&self) -> Self::Item;
}
impl Container for Vec<i32> {
// 指定关联类型 `Item` 为 `i32`
type Item = i32;
fn first(&self) -> Self::Item {
self[0]
}
}
impl Container for Vec<String> {
// 指定关联类型 `Item` 为 `String`
type Item = String;
fn first(&self) -> Self::Item {
self[0].clone()
}
}
代码挑战
尝试修改编辑器中提供的泛型代码以打印:
Item from int vector: 58 Item from str vector: literank.cn
Loading...
> 此处输出代码运行结果