我正在处理一个可以简化为以下代码的问题。结果是
error[E0499]: cannot borrow
*狗 as mutable more than once at a time.
。
错误的根源对我来说很清楚,但我想知道 - 解决它的正确方法是什么? 请注意,
Walker
和Swimmer
特征使用公共字段来减少剩余的energy
,所以对我来说,让Dog
来实现这两个特征是有意义的。
我想保持功能
move_around
不变,因为步行和游泳的顺序对我来说很重要:)任何帮助将不胜感激。
trait Swimmer {
fn swim(&mut self);
}
trait Walker {
fn walk(&mut self);
}
struct Fish {}
impl Swimmer for Fish {
fn swim(&mut self) {}
}
struct Turtle {}
impl Walker for Turtle {
fn walk(&mut self) {}
}
struct Dog {
energy: usize,
}
impl Swimmer for Dog {
fn swim(&mut self) {
self.energy -= 1;
}
}
impl Walker for Dog {
fn walk(&mut self) {
self.energy -= 1;
}
}
fn move_around(walker: &mut dyn Walker, swimmer: &mut dyn Swimmer) {
walker.walk();
swimmer.swim();
}
fn main() {
// This does not compile: error[E0499]: cannot borrow `*dog` as mutable more than once at a time
let dog = &mut Dog { energy: 100 };
move_around(dog, dog);
// Works fine.
// move_around(&mut Turtle {}, &mut Fish {});
}
我发现的可能解决方案之一是拆分借用 - 这意味着将
Walker
和 Swimmer
字段添加到 Dog
结构并将它们传递给函数,但共享状态使其变得复杂。
编辑
我想在这种情况下,我可以使用我想避免的
RefCell
,或者添加一个接受具有特征边界的泛型的新函数:
fn move_around<T: Walker + Swimmer>(entity: &mut T) {
entity.walk();
entity.swim();
}
您有多种选择:
Walker
和 Swimmer
。Walker
和 Swimmer
作为超级特征,为实现 Walker
和 Swimmer
的所有内容添加全面实现,并接受 &mut dyn WalkerAndSwimmer
。那就是:trait WalkerAndSwimmer: Walker + Swimmer {}
impl<T: ?Sized + Walker + Swimmer> WalkerAndSwimmer for T {}
fn move_around(v: &mut dyn WalkerAndSwimmer) {
v.walk();
v.swim();
}
这并不排除步行者和游泳者使用不同类型,只是需要为他们提供更多样板:定义一个结构体,将它们都作为字段并将
Walker
和 Swimmer
转发给他们,然后传递它。
&self
并将内部可变性(例如 RefCell
)放入结构内部。第二种是保持方法不变,但采用 &RefCell<dyn Walker>
,游泳运动员也一样。每种方法都有优点和缺点。