在static and dynamic dispatch的锈书部分中有关于此主题的一些基本背景,但tldr基本上是:在特征参考和其他一些情况(函数指针等)上调用方法)导致动态而不是静态调度。
所以,问:
在应用优化后,实际的运行时成本是多少?
例如,想象一下这组结构&性状:
struct Buffer;
struct TmpBuffer;
struct TmpMutBuffer;
impl BufferType for Buffer { ... }
impl BufferType for BufferTmp { ... }
impl BufferType for BufferTmpMut { ... }
impl Buffer2D for BufferType { ... }
impl Buffer2DExt for Buffer2D { ... }
特别注意这里的特征是在特征本身上实现的。
动态调度从结构引用上的Buffer2DExt调用方法的调用成本是多少?
最近有关于解除引用规则的问题What are Rust's exact auto-dereferencing rules?;这些规则是在编译时应用还是运行时?
答案 0 :(得分:17)
免责声明:这个问题相当开放,因此这个答案可能不完整。用比平时更大的盐粒来治疗它。
Rust使用一个简单的“虚拟表”来实现动态调度。此策略也用于you can see a study here的C ++。这项研究有点过时了。
间接费用
虚拟调度导致间接,这有多种原因导致成本:
优化间接
然而,编制者通过尽力优化间接来玷污水。if v.hasType(A) { v.A::call() } elif v.hasType(B) { v.B::call() } else { v.virtual-call() }
的模式;特殊外壳最可能的类型意味着在这种情况下常规调用,因此内联/常量传播/完全好的调用。由于一致性规则和隐私规则,后一种策略在Rust中可能相当有趣,因为它应该有更多可以证明完整“继承”图的情况。
单态化成本(和内联)
正如Shepmaster所推动的,替代品的成本。
在Rust中,您可以使用编译时多态而不是运行时多态;编译器将为每个独特的编译时参数组合发出一个版本的函数。这本身就有成本:
编译器可能能够将最终具有相同实现的特定函数合并在一起(例如,由于幻像类型),但是它仍然比生成的二进制文件(可执行文件和库)更大
与往常一样,你必须在你的情况下衡量什么是更有益的。