Rust 泛型与特性

泛型函数与结构体、trait 定义与实现、trait bound、以及动态分发。

Advanced
Key Points泛型是编译期单态化(零成本),`dyn Trait` 是运行期虚表(有开销)。

泛型函数

Rust
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
    let mut max = list[0];
    for &item in list.iter() {
        if item > max {
            max = item;
        }
    }
    max
}

fn main() {
    println!("{}", largest(&[1, 5, 3]));
    println!("{}", largest(&[1.5, 0.2, 3.7]));
    println!("{}", largest(&['a', 'z', 'm']));
}
Output
5
3.7
z

T: PartialOrd + Copy is a trait bound: T must be comparable and copyable. Without it item > max fails to compile — a generic function may only use declared capabilities.

泛型结构体

Rust
#[derive(Debug)]
struct Pair<T> {
    first: T,
    second: T,
}

impl<T: std::fmt::Display> Pair<T> {
    fn show(&self) {
        println!("({}, {})", self.first, self.second);
    }
}

// 只对特定类型实现
impl Pair<f64> {
    fn average(&self) -> f64 {
        (self.first + self.second) / 2.0
    }
}

fn main() {
    let p = Pair { first: 1, second: 2 };
    p.show();

    let f = Pair { first: 1.0, second: 2.0 };
    f.show();
    println!("{}", f.average());
}
Output
(1, 2)
(1, 2)
1.5

trait

Rust
trait Summary {
    // 必须实现
    fn summarize(&self) -> String;

    // 默认实现
    fn preview(&self) -> String {
        format!("{}...", &self.summarize()[..10.min(self.summarize().len())])
    }
}

struct Article {
    title: String,
    body: String,
}

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("{}: {}", self.title, self.body)
    }
}

struct Tweet {
    user: String,
    text: String,
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("@{}: {}", self.user, self.text)
    }

    fn preview(&self) -> String {
        self.text.clone()
    }
}

fn main() {
    let a = Article { title: "Rust".into(), body: "所有权很重要".into() };
    let t = Tweet { user: "tom".into(), text: "今天学了 trait".into() };

    println!("{}", a.summarize());
    println!("{}", t.summarize());
}
Output
Rust: 所有权很重要
@tom: 今天学了 trait

静态分发 vs 动态分发

Rust
fn static_dispatch<T: Summary>(item: &T) {
    println!("{}", item.summarize());
}

fn dynamic_dispatch(item: &dyn Summary) {
    println!("{}", item.summarize());
}

fn main() {
    let a = Article { title: "x".into(), body: "y".into() };
    static_dispatch(&a);
    dynamic_dispatch(&a);

    // dyn 才能放进同质容器
    let items: Vec<Box<dyn Summary>> = vec![
        Box::new(Article { title: "a".into(), body: "b".into() }),
        Box::new(Tweet { user: "u".into(), text: "t".into() }),
    ];
    for i in &items {
        println!("{}", i.summarize());
    }
}
Output
x: y
x: y
a: b
@u: t
FormDispatchCostUse
<T: Trait>静态,单态化零性能敏感、类型固定
impl Trait静态零参数或返回值
&dyn Trait动态,虚表一次间接调用混合类型集合
Generics are monomorphised: largest::<i32> and largest::<f64> compile to two separate bodies. Heavy generics bloat the binary and slow builds; dyn has one body at the cost of a vtable jump.

常见标准库 trait

TraitMethodMeaning
Displayfmt{} 打印
Debugfmt{:?} 打印
Cloneclone显式复制
Defaultdefault零值构造
From / Intofrom / into类型转换
Iteratornext迭代
Derefderef解引用与自动转换

Friends & Partners