我有一个具有以下结构的枚举:
enum Expression {
Add(Add),
Mul(Mul),
Var(Var),
Coeff(Coeff)
}
Run Code Online (Sandbox Code Playgroud)
每个变体的"成员"都是结构.
现在我想比较两个枚举是否有相同的变体.所以,如果我有
let a = Expression::Add({something});
let b = Expression::Add({somethingelse});
Run Code Online (Sandbox Code Playgroud)
cmpvariant(a, b)应该是true.我可以想象一个简单的双重match代码,它遍历两个枚举实例的所有选项.但是,如果它存在,我正在寻找一个更好的解决方案.如果没有,双重匹配会有开销吗?我想在内部我只是比较两个整数(理想情况下).
She*_*ter 28
从Rust 1.21.0开始,您可以使用std::mem::discriminant:
fn variant_eq(a: &Op, b: &Op) -> bool {
std::mem::discriminant(a) == std::mem::discriminant(b)
}
Run Code Online (Sandbox Code Playgroud)
这很好,因为它可以非常通用:
fn variant_eq<T>(a: &T, b: &T) -> bool {
std::mem::discriminant(a) == std::mem::discriminant(b)
}
Run Code Online (Sandbox Code Playgroud)
在Rust 1.21.0之前,我将匹配两个参数的元组并忽略元组的内容_或..:
struct Add(u8);
struct Sub(u8);
enum Op {
Add(Add),
Sub(Sub),
}
fn variant_eq(a: &Op, b: &Op) -> bool {
match (a, b) {
(&Op::Add(..), &Op::Add(..)) => true,
(&Op::Sub(..), &Op::Sub(..)) => true,
_ => false,
}
}
fn main() {
let a = Op::Add(Add(42));
let b = Op::Add(Add(42));
let c = Op::Add(Add(21));
let d = Op::Sub(Sub(42));
println!("{}", variant_eq(&a, &b));
println!("{}", variant_eq(&a, &c));
println!("{}", variant_eq(&a, &d));
}
Run Code Online (Sandbox Code Playgroud)
我冒昧地重命名了这个函数,因为枚举的组件被称为变体,实际上你正在测试它们是否相等,而不是比较它们(通常用于排序/排序).
为了提高性能,让我们看看Rust 1.16.0在发布模式下生成的LLVM IR.该锈病游乐场可以轻松地告诉你这一点:
define internal fastcc zeroext i1 @_ZN10playground10variant_eq17h3a88b3837dfe66d4E(i8 %.0.0.val, i8 %.0.0.val1) unnamed_addr #0 {
entry-block:
%switch2 = icmp eq i8 %.0.0.val, 1
%switch = icmp ne i8 %.0.0.val1, 1
br i1 %switch2, label %bb5, label %bb4
bb3: ; preds = %bb5, %bb4
br label %bb6
bb4: ; preds = %entry-block
br i1 %switch, label %bb6, label %bb3
bb5: ; preds = %entry-block
br i1 %switch, label %bb3, label %bb6
bb6: ; preds = %bb5, %bb4, %bb3
%_0.0 = phi i1 [ false, %bb3 ], [ true, %bb4 ], [ true, %bb5 ]
ret i1 %_0.0
}
Run Code Online (Sandbox Code Playgroud)
简短版本是我们在一个枚举变体上进行切换,然后与另一个枚举变体进行比较.它总体上非常有效,但我很惊讶它不仅仅直接比较变量数字.也许这是优化传递可以解决的问题?
如果你想要一个宏来生成函数,这样的事情可能是一个好的开始.
struct Add(u8);
struct Sub(u8);
macro_rules! foo {
(enum $name:ident {
$($vname:ident($inner:ty),)*
}) => {
enum $name {
$($vname($inner),)*
}
impl $name {
fn variant_eq(&self, b: &Self) -> bool {
match (self, b) {
$((&$name::$vname(..), &$name::$vname(..)) => true,)*
_ => false,
}
}
}
}
}
foo! {
enum Op {
Add(Add),
Sub(Sub),
}
}
fn main() {
let a = Op::Add(Add(42));
let b = Op::Add(Add(42));
let c = Op::Add(Add(21));
let d = Op::Sub(Sub(42));
println!("{}", Op::variant_eq(&a, &b));
println!("{}", Op::variant_eq(&a, &c));
println!("{}", Op::variant_eq(&a, &d));
}
Run Code Online (Sandbox Code Playgroud)
虽然宏确实有局限性 - 所有变体都需要有一个变体.支持单元变体,具有多种类型的变体,结构变体,可见性等都是非常困难的.也许程序宏会使它更容易一些.
| 归档时间: |
|
| 查看次数: |
4454 次 |
| 最近记录: |