08-栈上动态分发
栈上动态分发 — Rust Design Patterns
2 分钟阅读
译文 · 基于 Rust Design Patterns
原文链接: https://rust-unofficial.github.io/patterns/idioms/on-stack-dyn-dispatch.html
栈上动态分发
描述
我们可以对多个值进行动态分发,但为此需要声明多个变量,以绑定不同类型的对象。 为了按需延长生命周期,我们可以使用延迟条件初始化,如下所示:
示例
| |
动机
Rust 默认会将代码单态化。这意味着会为所用的每种类型生成一份代码副本,并分别优化。 这固然能让热路径上的代码非常快,但也会在性能并不关键的地方膨胀代码,从而耗费编译时间和缓存。
幸运的是,Rust 允许我们使用动态分发,但我们必须显式请求它。
优点
我们不需要在堆上分配任何东西。也不需要初始化稍后不会用到的东西,
更不需要把后续整段代码单态化,以便同时适用于 File 或 Stdin。
缺点
在 Rust 1.79.0 之前,这段代码需要两个带延迟初始化的 let 绑定,
比基于 Box 的版本有更多活动部件:
// 我们仍需标明类型才能得到动态分发。
let readable: Box<dyn io::Read> = if arg == "-" {
Box::new(io::stdin())
} else {
Box::new(fs::File::open(arg)?)
};
// 在此处从 `readable` 读取。
幸运的是,这一缺点现已不复存在。太好了!
讨论
自 Rust 1.79.0 起,编译器会在函数作用域内尽可能延长 & 或 &mut 中临时值的生命周期。
这意味着我们可以在这里直接使用 &mut 值,而不必担心把内容放到某个 let 绑定中
(那是延迟初始化所需要的,也是该变更之前所用的解决方案)。
我们仍然为每个值准备了一个位置(即便该位置是临时的),编译器知道每个值的大小, 且每个被借用的值都比从它借出的所有引用活得更久。