0Pricing
Learn Rust Coding · 课时

静态分派与动态分派

权衡取舍

静态分派与动态分派 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 4 节课。

两种分派方式

调用特征方法时,Rust 必须决定运行哪个具体实现。有两种策略:静态分派(在编译时决定)和动态分派(在运行时决定)。

使用泛型进行静态分派

泛型函数使用静态分派。编译器会为每种具体类型生成一个专用副本——这个过程称为单态化。

trait Area { fn area(&self) -> f64; }
struct Square { s: f64 }
impl Area for Square { fn area(&self) -> f64 { self.s * self.s } }

fn print_area<T: Area>(shape: &T) {
    println!("{}", shape.area());
}

fn main() {
    print_area(&Square { s: 4.0 });
}

单态化

对于您调用时使用的每种类型,编译器都会生成一个专用版本的函数。方法调用会变成无需查找的直接调用,因此速度与手写代码一样快。

使用 dyn 进行动态分派

特征对象使用动态分派。一个函数可以处理所有类型;方法地址会在运行时通过虚函数表找到。

trait Area { fn area(&self) -> f64; }
struct Square { s: f64 }
impl Area for Square { fn area(&self) -> f64 { self.s * self.s } }

fn print_area(shape: &dyn Area) {
    println!("{}", shape.area());
}

fn main() {
    print_area(&Square { s: 4.0 });
}

虚函数表

特征对象是一个胖指针:其中一部分指向数据,另一部分指向列出方法地址的虚函数表。每次调用都会在此表中进行索引。

这次额外的间接访问就是运行时开销。

速度权衡

静态分派每次调用更快,并且可以内联,但会生成更多机器代码。动态分派会增加极小的间接访问开销,但能保持代码体积较小。

对于大多数应用,两者差异可以忽略;请根据灵活性进行选择。

代码体积权衡

使用多种类型调用泛型函数会创建许多副本,可能使二进制文件膨胀。单个 dyn 函数可以避免这种重复。

这就是库有时会在内部优先使用特征对象的原因。

灵活性权衡

泛型要求每个调用位置使用一种具体类型,因此无法在集合中存放混合类型。特征对象可以做到这一点。如果您需要异构列表,动态分派就是答案。

trait Area { fn area(&self) -> f64; }
struct Square { s: f64 }
struct Rect { w: f64, h: f64 }
impl Area for Square { fn area(&self) -> f64 { self.s * self.s } }
impl Area for Rect { fn area(&self) -> f64 { self.w * self.h } }

fn main() {
    let shapes: Vec<Box<dyn Area>> = vec![Box::new(Square { s: 2.0 }), Box::new(Rect { w: 3.0, h: 4.0 })];
    let total: f64 = shapes.iter().map(|s| s.area()).sum();
    println!("{}", total);
}

结合使用两者

您可以将两者结合起来:泛型函数可以在边界处接受 impl Trait,并在内部将值存储为 Box<dyn Trait>。请在适合的地方使用适合的方式。

选择指南

快速规则:

  • 每次调用只有一种类型,且位于热点路径?使用泛型(静态分派)。
  • 集合中包含混合类型?使用 dyn(动态分派)。
  • 担心二进制文件大小?倾向于使用 dyn。

两者在关键之处都没有额外开销

Rust 不会添加您没有要求的开销。泛型在运行时没有成本;特征对象只产生一次指针间接访问的开销。您可以明确选择这种权衡。

快速检查

检验您对分派的理解。

回顾

您比较了两种分派方式:

  • 静态(泛型):经过单态化,速度快,二进制文件较大,每次调用使用一种类型
  • 动态(dyn):查找虚函数表,灵活,代码较小,支持混合类型集合
  • 请根据对灵活性、性能和二进制文件大小的需求进行选择

常见问题解答

「静态分派与动态分派」课时是免费的吗?

是的 — 「静态分派与动态分派」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 4 节课。

「静态分派与动态分派」这节课中我会学到什么?

权衡取舍 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Learn Rust Coding 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「静态分派与动态分派」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Learn Rust Coding 课中编写并运行代码吗?

能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 定义特征
  2. 特征对象与 dyn
  3. 静态分派与动态分派
  4. 默认方法
← 返回 Learn Rust Coding