Wang's blog

六、泛型

Published on

泛型是用于编写功能确定,类型待定的代码模板的机制,可以有效减少代码冗余。类似于C++中的模板。

在函数中使用

// 定义一个使用泛型的函数
fn foo<T>(arg: T) {
    ...
}

// 编译器自动识别T为i32
foo(1);
// 编译器自动识别T为&str
foo("string");

// 手动设置T为i32
foo::<i32>(1);

在结构体中使用

// 定义一个使用泛型的结构体
struct Point<T> {
    x: T,
    y: T,
}

// 自动识别T为i32
let integer = Point { x: 5, y: 10 };
// 自动识别T为f64
let float = Point { x: 1.0, y: 4.0 };
// 错误,x与y必须具有相同的类型
let wont_work = Point { x: 5, y: 4.0 };

// 手动设置T为u8
let uint8 = Point::<u8> { x: 1, y: 2 };

在枚举中使用

std库中的Option与Result是非常常用的使用了泛型的枚举结构。

enum Option<T> {
    Some(T),
    None,
}

enum Result<T, E> {
    Ok(T),
    Err(E),
}

在实现中使用

// 如果实现泛型方法,需要在impl后使用泛型
impl<T> Point<T> {
    fn x(&self) -> &T {
        &self.x
    }
}

// 只为Point<f32>类型实现方法
impl Point<f32> {
    fn x(&self) -> &f32 {
        &self.x
    }
}

在特性中使用

// 声明一个泛型特性
trait DoubleDrop<T> {
    fn double_drop(self, _: T);
}

// 实现上述特性
impl<T, U> DoubleDrop<T> for U {
    fn double_drop(self, _: T) {}
}

特性范围(trait bound)

在使用泛型时,有时需要要求参数实现指定的特性。

// 要求参数T实现Display特性
fn printer<T: Display>(t: T) {
    println!("{}", t);
}

// 要求参数实现多个特性
fn compare_prints<T: Debug + Display>(t: &T) {
    println!("Debug: `{:?}`", t);
    println!("Display: `{}`", t);
}

// 使用where子句使代码更加易读
impl <A: TraitB + TraitC, D: TraitE + TraitF> MyTrait<A, D> for YourType {}
impl <A, D> MyTrait<A, D> for YourType where
    A: TraitB + TraitC,
    D: TraitE + TraitF {}