我在探索 Rust 的时候遇到了这个术语。
我看到了各种不同的解释,但仍然不太明白其中的思想。
在嵌入式 Rust 书籍中,它说道:
类型状态也是零成本抽象的一个很好的例子
- 将某些行为移动到编译时执行或分析的能力。
这些类型状态不包含任何实际数据,而是用作标记。
由于它们不包含任何数据,在运行时内存中也没有实际表示:
这是否意味着运行时更快,因为运行时没有内存?
如果有人能以易懂的方式解释一下,我将不胜感激。
我在探索 Rust 的时候遇到了这个术语。
我看到了各种不同的解释,但仍然不太明白其中的思想。
在嵌入式 Rust 书籍中,它说道:
类型状态也是零成本抽象的一个很好的例子
- 将某些行为移动到编译时执行或分析的能力。
这些类型状态不包含任何实际数据,而是用作标记。
由于它们不包含任何数据,在运行时内存中也没有实际表示:
这是否意味着运行时更快,因为运行时没有内存?
如果有人能以易懂的方式解释一下,我将不胜感激。
零成本抽象是指在执行速度或内存使用方面没有运行时成本的抽象。
相比之下,虚拟方法是一个很好的例子,它是一种昂贵的抽象:在许多面向对象语言中,方法调用者的类型是在运行时确定的,这需要维护一个查找表(运行时内存使用),然后实际执行查找(每个方法调用的运行时开销,可能至少需要额外的指针解引用)以确定调用哪个版本的方法。另一个很好的例子是垃圾回收:为了不必担心内存分配的细节,你需要付出GC暂停的代价。
然而,Rust大多数情况下都试图采用零成本抽象:这些抽象可以让你既能拥有优雅的代码,又能保证编译器能够安全、正确地将其转换为不带有额外间接性/内存使用的形式。事实上,我所知道的(如果我错了,请更加了解的人纠正我)在Rust中真正需要在运行时支付的唯一费用是边界检查和dyn
(请参见上面关于虚拟方法的部分)。
dyn
,比如 &dyn Trait
时,Rust 才会使用动态分发。否则,即使是引用,它也总是使用编译时分发。 - Devbar.bar()
的调用实际上是通过内联方式进行的,而不是使用 &dyn Bar
虚函数表。这是因为编译器足够聪明,能够识别出 bar
始终引用一个 Foo
实例,即使它是一个 trait 对象。 - Jmb