63·进阶特性进阶

dyn Trait 动态分发

dyn Trait 动态分发

学习目标

  1. 理解动态分发 vs 静态分发
  2. 掌握 dyn Trait 用法
  3. 理解 vtable

核心概念

静态分发 vs 动态分发

// 静态分发:编译时确定类型,单态化
fn print_static(item: &impl std::fmt::Display) {
    println!("{}", item);
}

// 动态分发:运行时确定类型,通过 vtable
fn print_dynamic(item: &dyn std::fmt::Display) {
    println!("{}", item);
}

trait 对象

trait Animal {
    fn speak(&self) -> String;
}

struct Dog;
struct Cat;

impl Animal for Dog {
    fn speak(&self) -> String { "汪汪".to_string() }
}

impl Animal for Cat {
    fn speak(&self) -> String { "喵喵".to_string() }
}

fn main() {
    // Box<dyn Trait>
    let animals: Vec<Box<dyn Animal>> = vec![
        Box::new(Dog),
        Box::new(Cat),
    ];

    for animal in &animals {
        println!("{}", animal.speak());
    }
}

对象安全

// trait 对象的要求:
// 1. 方法不能返回 Self
// 2. 方法不能有泛型参数

// ❌ 不是对象安全的
trait Cloneable {
    fn clone(&self) -> Self;
}

// ✅ 对象安全
trait Drawable {
    fn draw(&self);
}

dyn 与生命周期

// 静态生命周期
fn create() -> &'static dyn std::fmt::Display {
    &42
}

// 引用
fn process(item: &dyn std::fmt::Display) {
    println!("{}", item);
}

// Box
fn create_box() -> Box<dyn std::fmt::Display> {
    Box::new(42)
}

小结

概念说明
&dyn Traittrait 引用(动态分发)
Box<dyn Trait>trait 对象(堆分配)
vtable虚函数表,运行时查找方法
对象安全不能返回 Self 或有泛型
性能动态分发有间接调用开销

练习编辑器

rust
Loading...