“零成本抽象”是什么意思?

Sam*_*iin 36 rust

我在探索 Rust 时遇到了这个术语。

我看到了对此的不同解释,但仍然不太明白。

The Embedded Rust Book中,它说

类型状态也是零成本抽象的一个很好的例子

  • 将某些行为移动到编译时执行或分析的能力。

这些类型状态不包含实际数据,而是用作标记。

由于它们不包含数据,因此它们在运行时在内存中没有实际表示:

这是否意味着运行时更快,因为运行时没有内存?

如果有人能以易于理解的方式解释它,我将不胜感激。

Mik*_*maa 74

零成本抽象意味着添加更高级别的编程概念,如泛型、集合等,不会带来运行时成本,只有编译时成本(代码编译速度会更慢)。零成本抽象上的任何操作都与使用低级编程概念(例如 for 循环、计数器、ifs 和使用原始指针)手动编写匹配功能一样快。

或者另一种看待这一点的方式是,使用零成本抽象工具、函数、模板、类等可以“零成本”地提高代码的性能。


Jar*_*ith 19

零成本抽象是指在执行速度或内存使用方面不承担运行时成本的抽象。

相比之下,虚拟方法是成本高昂的抽象的一个很好的例子:在许多面向对象语言中,方法调用者的类型是在运行时确定的,这需要维护一个查找表(运行时内存使用),然后实际执行查找(每个方法的运行时开销)调用,可能至少是一个额外的指针取消引用)与运行时类型以确定要调用的方法的版本。另一个很好的例子是垃圾收集:作为回报,你可以不用担心内存分配的细节,但你会付出 GC 暂停的代价。

Rust 主要尝试实现零成本抽象:即让你鱼与熊掌兼得。编译器可以安全、正确地转换为不承担额外间接/内存使用的形式。事实上,据我所知(如果我错了,有更多知识的人会纠正我),在 Rust 中运行时真正需要付出的代价就是边界检查dyn(请参阅上面有关虚拟方法的部分)。

  • Rust 具有提供运行时虚拟函数行为的特征(例如 [this](/sf/answers/3135049361/)) (4认同)
  • 特征可以在运行时或编译时分派。如果您有一个“struct Foo: Bar”和一个变量“let foo = Foo{}”,那么从“Bar”调用一个方法将在编译时调度(零成本)。但是,如果您的变量是“Bar”引用:“let bar = &foo as &Bar”,则将在运行时使用与大多数 OO 语言相同类型的查找表完成调度(除非优化器能够返回到“ Foo` 类型,某些 OO 语言也可以这样做)。 (4认同)
  • 好吧,看来 Rust 是“聪明”的,因为它会在可能的情况下“去虚拟化”特征使用(至少我是这么读的[这篇博文](https://blog.rust-lang.org/2015/05 /11/traits.html)戴着我的 C++ 眼镜)。我认为这可以归结为 Rust 为静态和动态调度提供了统一的语法。 (2认同)

小智 7

零成本抽象的概念最初来自函数世界。然而,该术语来自 C++。根据 Bjarne Stroustrup 的说法,

\n
\n

一般来说,C++ 实现遵循\n零开销原则:你不使用什么,就不需要付费。更进一步:你所使用的东西,你无法\xe2\x80\x99t 手工编写更好的代码。

\n
\n

这句话以及大多数答案都未能完整地表达这个想法,因为没有明确说明这些内容的上下文。

\n

如果世界上只有一种编程语言:无论是 Rust 还是 C++,零成本抽象将与大多数其他编译器优化没有区别。这里的含义是,有无数其他语言可以让您执行与 Rust 或 C++ 相同的操作,但成本不为零且通常是特定于运行时的。

\n

  • @mkrieger1不需要引用,很明显,函数式编程是一种完美的例子,它是一种强调使用纯函数、不可变数据和声明性结构来创建易于推理和维护的程序的编程风格,零-成本抽象。 (2认同)
  • @JulianoSilva 取决于您将抽象与什么进行比较。不可变数据意味着您将执行写时复制而不是就地操作(这就是为什么游戏和矩阵计算在 FP 中成本高昂)。它还需要GC(或其他一些自动内存管理)来清理未使用的数据(尽管从技术上讲,Haskell的gc“保存已使用的数据”而不是“收集垃圾”) (2认同)