我想做点什么
impl Widget {
fn foo(self, rhs: Widget) -> Self {
// Some stuff
}
fn update(&mut self, rhs: Widget) {
*self = (*self).foo(rhs)
}
}
但是编译器抱怨“无法摆脱借来的上下文”。什么是正确的方法?
答案 0 :(得分:3)
反过来说:
impl Widget {
fn op(mut self, rhs: Widget) -> Self {
self.update(rhs);
self
}
fn update(&mut self, rhs: Widget) {
// Some stuff
}
}
你不能移出借来的指针,因为移动使得源无法使用,但由于你不拥有源,这些信息必须传播回所有者,Rust不支持这一点。
您可能会说"但我会在函数返回之前为*self
分配一个新值!" 。问题在于,如果移动和分配之间存在恐慌,*self
仍然没有有效值。如果丢弃self
不是无操作,则这尤其成问题(尽管Rust不关心如果丢弃是无操作或不在此处)。
答案 1 :(得分:1)
一种选择是使用take_mut
包,它提供完全符合您要求的take
功能:
take
允许从T
中取出&mut T
,对其执行任何操作(包括使用它),并生成另一个T
以放回&mut T
}。
正如Francis Gagné所指出的,这样做的问题是,如果发生恐慌,&mut
引用将处于无效状态,这可能导致未定义的行为。 take_mut
方法是:
在
take
期间,如果发生恐慌,整个过程将会退出,因为没有有效的T
可以放回&mut T
。
以下是使用take
的代码:
extern crate take_mut;
struct Widget;
impl Widget {
fn foo(self, rhs: Widget) -> Self {
self
}
fn update(&mut self, rhs: Widget) {
take_mut::take(self, |s| s.foo(rhs));
}
}