在 Rust 中更新枚举变量数据时避免双重可变引用

问题描述 投票:0回答:1

(使用 Rust 1.74.1)

我有这个设置:

struct DataA {
    a: i32
}

struct DataB {
    b: i32
}

enum Data {
    TypeA(DataA),
    TypeB(DataB),
    // TypeC etc...
}

struct Struct {
    field: i32,
    // other fields
    data: Data,
}

impl Struct {
    fn foo(&mut self) -> i32 {
        self.field += 5;
        return 5;
    }
}

我想为

bar()
实现一个方法(
Struct
),将
TypeA(DataA)
a
设置为
foo()
的返回值,并且如果
Struct
.
data
不执行任何操作不是
TypeA

最初,我尝试过

fn bar(&mut self) {
    let Data::TypeA(data) = &mut self.data else {
        return;
    };
    data.a = self.foo();
}

但这不起作用,因为我

cannot borrow `*self` as mutable more than once at a time

经过一番尝试,我发现了一个错误

let Data::TypeA(..) = self.data else {
    return;
};
self.data = Data::TypeA(DataA{ a: self.foo() });

它可以工作,但冗长且麻烦(例如,向 DataA 添加更多字段)。

请注意,

foo()
永远不会改变
Struct
data
,并且必须在after检查类型是否匹配后运行。

有没有更好的方法可以在不更改设置的情况下编写此代码? 如果没有,最惯用的方法是什么?

rust struct enums
1个回答
0
投票

请注意,

foo()
永远不会改变
Struct
data
,并且必须在检查类型是否匹配后运行。

我认为这是主要问题。虽然你说 foo 从不这样做,但你的 API 并没有反映这一点。如果可以,编译器会让你这样做。

如果您将

field
封装在自己的数据类型中,并将
foo
函数移动到那里,那么您实际上告诉编译器您只在此函数中修改
field

struct DataA {
    a: i32,
}

struct DataB {
    b: i32,
}

enum Data {
    TypeA(DataA),
    TypeB(DataB),
    // TypeC etc...
}

struct FieldData {
    field: i32,
}

impl FieldData {
    fn foo(&mut self) -> i32 {
        self.field += 5;
        return 5;
    }
}

struct Struct {
    field: FieldData,
    // other fields
    data: Data,
}

impl Struct {
    fn bar(&mut self) {
        if let Data::TypeA(data) = &mut self.data {
            data.a = self.field.foo();
        }
    }
}

像这样将一个结构体拆分为多个部分是解决此类问题的一个非常常见的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.