有没有一种方法可以创建一个更新了一些字段值的枚举副本



我有一个带有几个记录变体的枚举:

enum A {
Var1 { a: i64, b: i64 },
Var2 { c: i32, d: i32 },
}

我想创建这样一个枚举的修改副本(每个变体都有不同的行为)。我知道我能做到:

match a {
A::Var1 { a, b } => A::Var1 { a: new_a, b },
A::Var2 { c, d } => A::Var2 { c, d: new_d },
}

然而,每个变体都有相当多的字段,我不希望显式地传递所有字段。有没有办法说"克隆这个枚举,除了将这个值用于字段x而不是克隆的值"?

不完全是。有"功能记录更新语法",但仅适用于structs:

struct Foo {
bar: u8,
baz: u8,
quux: u8,
}
fn foo() {
let foobar = Foo {
bar: 1,
baz: 2,
quux: 3,
};
let bazquux = Foo { baz: 4, ..foobar };
}

在不为每个变体创建结构的情况下,你能做的最好的事情是这样的:

let mut altered = x.clone();
match &mut altered {
A::Var1 { a, .. } => *a = new_a,
A::Var2 { d, .. } => *d = new_d,
};
altered

基于Rust的设计,恐怕您遇到了其中一个限制,而您唯一真正的解决方案是就地突变并编写一个或四个突变函数。

枚举的问题在于需要match才能对它们执行任何操作。在那之前,Rust对结构的实际内容知之甚少或推断甚少。另一个问题是,它缺乏任何类似反射的功能,无法查询类型并确定它是否有字段,并且除了完全匹配所有内容之外,无法执行任何操作。

老实说,最干净的方法实际上可能取决于你突变的目的。它们是基于某种业务关注点对enum进行的一组定义的更改吗?如果是这样的话,您可能实际上想要将您的逻辑封装到一个特性扩展中,并使用它来封装逻辑。

例如,考虑一个非常做作的例子。我们正在构建一个应用程序,它必须处理不同的项目并对它们征税。上述税收取决于产品类型,出于某种原因,我们所有的产品都用enum的变体表示,如下所示:#[派生(调试)]enum项{食物{价格:u8,卡路里:u8},技术{价格:u8},}

trait TaxExt {
fn apply_tax(&mut self);
}
impl TaxExt for Item {
fn apply_tax(&mut self) {
match self {
&mut Item::Food {
ref mut price,
calories: _,
} => {
// Our food costs double, for tax reasons
*price *= 2;
}
&mut Item::Technology { ref mut price } => {
// Technology has a 1 unit tax
*price += 1;
}
}
}
}
fn main() {
let mut obj = Item::Food {
price: 3,
calories: 200,
};
obj.apply_tax();
println!("{:?}", obj);
}

操场

假设可以这样拆分逻辑,这可能是构建逻辑的最干净的方法。

最新更新