[英]How do I pass a mutable reference to a method on an object that belongs to that reference?
我有一个属于结构实例 B 的结构实例 A。我需要通过调用父对象对这些数据进行一些处理。
struct A {
val : u8
}
struct B {
data : u8,
a : A
}
impl A {
pub fn process(&mut self, b : &mut B) {
println!("Processing {} - {}", b.data, self.val);
//do stuff with val and data...
}
}
impl B {
pub fn process(&mut self) {
self.a.process(self);
}
}
fn main() {
let mut b = B {
data : 0,
a : A {
val : 3
}
};
b.process();
}
当我尝试调用 b.process() 时,出现以下故障:
error[E0499]: cannot borrow `self.a` as mutable more than once at a time
--> src/main.rs:47:9
|
47 | self.a.process(self);
| ^^^^^^^-------^----^
| | | |
| | | first mutable borrow occurs here
| | first borrow later used by call
| second mutable borrow occurs here
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:47:24
|
47 | self.a.process(self);
| ---------------^^^^-
| | | |
| | | second mutable borrow occurs here
| | first borrow later used by call
| first mutable borrow occurs here
当不需要可变引用时,所有这些都可以正常工作。
所以我的问题是,当我需要两个结构之间的这种类型的关系时,正确的方法是什么?
你不能这样做违反了 Rusts 别名规则,你将有两个对A
可变引用,一个是直接的,一个是通过B
间接引用的。 如果你真的想要,你可以使用内部可变性( RefCell
, Mutex
,...)但正如 kaya3 指出的那样,即使从 OO 的角度来看,你建议的实现似乎也很奇怪。 如果它仍然需要B
,我会直接在B
上实现它,而无需间接访问。
在 Rust 中,您可以拥有单个可变引用或多个不可变引用,或者换句话说:单个编写器/多个读取器。
let mut a = 0; // Only mutable variables can be written to
let a1 = &a;
let a2 = &a; // Readers can be many
// This is an error:
let a3 = &mut a; // You cannot write to `a` while it is borrowed for reading
print!("{} {} {}", a1, a2, a3)
let mut a = 0;
let a1 = &mut a; // You can have a single writer
// This is an error:
let a2 = &mut a; // But there can be only one
// This is also an error:
let a3 = &a; // You cannot read while `a` can be written to
print!("{} {} {}", a1, a2, a3)
按照这个逻辑我们可以对代码进行一些观察
impl A {
// this implies that both self and B can change
pub fn process(&mut self, b: &mut B) {
println!("Processing {} - {}", b.data, self.val);
//do stuff with val and data...
}
pub fn process_changes_a(&mut self, b: &B) {
println!("Processing {} - {}", b.data, self.val);
}
pub fn process_changes_b(&self, b: &mut B) {
println!("Processing {} - {}", b.data, self.val);
}
}
impl B {
pub fn process(&mut self) {
// it's possible to use clones to work around this
// however it's probably better to refactor the logic
// let's see what happens when using clones
let mut tmp_self = self.clone();
let mut tmp_a = self.a.clone();
// this can modify both self.a and tmp_self
self.a.process(&mut tmp_self);
// now self and tmp_self could be different
// does self need to have the value of the &mut B?
// note: this clone is only necessary for
// the other examples to compile
*self = tmp_self.clone();
// or does only self.a need to change?
tmp_a.process(self);
self.a = tmp_a;
// or should the original self.a stay the same?
self.data = tmp_self.data;
}
pub fn process_changes_a(&mut self) {
// you still need a clone of self.a
// otherwise A::process_changes_a could
// modify a through self while reading b.a
let mut tmp_a = self.a.clone();
tmp_a.process_changes_a(self);
self.a = tmp_a;
}
pub fn process_changes_b(&mut self) {
// you still need a clone of self.a
// otherwise A::process_changes_b could
// modify a through b.a while reading self
let tmp_a = self.a.clone();
tmp_a.process_changes_b(self);
}
pub fn process_on_self(&mut self) {
// if you need to modify both self and self.a
// it might be best to have the method directly on B
println!("Processing {} - {}", self.data, self.a.val);
}
}
问题实际上来自这样一个事实,即A::process(&mut self, b: &mut B)
不知道self
和ba
在从B
调用时引用相同的值并期望它们不同。 您可以通过使用克隆或副本使其工作,但这可能是不必要的。
就个人而言,我可能会尝试将process()
的逻辑完全移至 B。在您的示例中,A 依赖于 B,但 B 也依赖于 A。这将使只有 B 依赖于 A,这使事情变得更简单.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.