【发布时间】:2020-09-11 13:51:12
【问题描述】:
如果已经知道需要动态多态性的代码中涉及的所有有限数量的类型,则与使用 Box 相比,使用 enum 的性能会更好,因为后者使用动态内存分配,您需要使用具有虚函数调用的特征对象。
也就是说,与使用 std::variant 和 std::visit 的 C++ 中的等效代码相比,在这种情况下,Rust 似乎涉及更多样板代码,至少对我来说是这样(我还没有学会使用过程宏)。在这里举个例子:我有一堆struct 类型:
struct A {
// ...
}
struct B {
// ...
}
// ...
struct Z {
// ...
}
它们都实现了 AlphabetLetter 特征,即:
trait AlphabetLetter {
fn some_function(&self);
}
由于涉及的类型集是已知且有限的,我想使用enum:
enum Letter {
AVariant(A),
BVariant(B),
// ...
ZVariant(Z),
}
这里我们已经有了第一个样板:我需要为涉及的每个类型变体的enum 值添加一个名称。但真正的问题是:enumLetter 本身就是一个AlphabetLetter,它只是表示我们在运行时不知道它是哪个字母的事实。所以我开始为它实现 trait:
impl AlphabetLetter for Letter {
fn some_function(&self) {
match self {
Letter::AVariant(letter) => letter.some_function();
Letter::BVariant(letter) => letter.some_function();
// ...
Letter::ZVariant(letter) => letter.some_function();
}
}
}
是的,这很容易变成很多代码,但我没有找到其他方法。在 C++ 中,多亏了泛型 lambda,人们可以只使用 std::visit 和 std::variant,而且它是单行的。如果不手动为 enum 中的每个变体中的特征 X 中的每个函数编写所有模式匹配,我怎么能做到这一点?
【问题讨论】:
-
没有多态性也没有动态调度,因为类型是静态已知的。
-
IIUC,C++ 模板是无类型的,使得
std::visit在功能上类似于使用 Rust 宏(请注意,C 宏完全是另一回事)。在 C++ 中为这种便利性付出的代价是在使用时报告类型错误而不是声明,并且在 lambda 中执行不兼容的操作的错误可能是……不透明的。 -
(另请注意,过程宏和声明性宏是不同类型的宏;声明性宏更容易,并且足以使这种事情工作而无需太多重复。)
-
我认为最好的解决方案是本地特征对象once they become available。这将消除对动态内存分配的需求,在这种情况下,我认为虚函数调用与您的
match语句非常相似(并且可能更快)。
标签: enums rust variant run-time-polymorphism