如何更新对不可复制类型的可变引用?
How to update a mutable reference to a noncopyable type?
我想做类似的事情
impl Widget {
fn foo(self, rhs: Widget) -> Self {
// Some stuff
}
fn update(&mut self, rhs: Widget) {
*self = (*self).foo(rhs)
}
}
但编译器抱怨 "cannot move out of borrowed context." 执行此操作的正确方法是什么?
反过来做:
impl Widget {
fn op(mut self, rhs: Widget) -> Self {
self.update(rhs);
self
}
fn update(&mut self, rhs: Widget) {
// Some stuff
}
}
你不能移出借用的指针,因为移动会使源不可用,但由于你不拥有源,该信息必须传播回所有者,而 Rust 不支持。
你可能会说 "but I'm assigning a new value to *self
before the function returns!"。这样做的问题是,如果移动和赋值之间存在恐慌,*self
仍将没有有效值。如果丢弃 self
不是空操作,这尤其成问题(尽管 Rust 不关心这里是否丢弃是空操作)。
一种选择是使用 take_mut
crate,它提供了 take
功能,可以完全满足您的需求:
take
allows for taking T
out of a &mut T
, doing anything with it including consuming it, and producing another T
to put back in the &mut T
.
正如 所指出的,这样做的问题是如果发生恐慌,&mut
引用将处于无效状态,这可能导致未定义的行为。 take_mut
方法是:
During take
, if a panic occurs, the entire process will be exited, as there's no valid T
to put back into the &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));
}
}
我想做类似的事情
impl Widget {
fn foo(self, rhs: Widget) -> Self {
// Some stuff
}
fn update(&mut self, rhs: Widget) {
*self = (*self).foo(rhs)
}
}
但编译器抱怨 "cannot move out of borrowed context." 执行此操作的正确方法是什么?
反过来做:
impl Widget {
fn op(mut self, rhs: Widget) -> Self {
self.update(rhs);
self
}
fn update(&mut self, rhs: Widget) {
// Some stuff
}
}
你不能移出借用的指针,因为移动会使源不可用,但由于你不拥有源,该信息必须传播回所有者,而 Rust 不支持。
你可能会说 "but I'm assigning a new value to *self
before the function returns!"。这样做的问题是,如果移动和赋值之间存在恐慌,*self
仍将没有有效值。如果丢弃 self
不是空操作,这尤其成问题(尽管 Rust 不关心这里是否丢弃是空操作)。
一种选择是使用 take_mut
crate,它提供了 take
功能,可以完全满足您的需求:
take
allows for takingT
out of a&mut T
, doing anything with it including consuming it, and producing anotherT
to put back in the&mut T
.
正如 &mut
引用将处于无效状态,这可能导致未定义的行为。 take_mut
方法是:
During
take
, if a panic occurs, the entire process will be exited, as there's no validT
to put back into the&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));
}
}