Reference 如何将可变引用更新为不可复制类型?

Reference 如何将可变引用更新为不可复制类型?,reference,copy,rust,move,mutable,Reference,Copy,Rust,Move,Mutable,我想做一些像 impl Widget { fn foo(self, rhs: Widget) -> Self { // Some stuff } fn update(&mut self, rhs: Widget) { *self = (*self).foo(rhs) } } 但编译器抱怨“无法脱离借用的上下文”。正确的方法是什么?换一种方法: impl Widget { fn op(mut self, rh

我想做一些像

impl Widget {
    fn foo(self, rhs: Widget) -> Self {
        // Some stuff
    }

    fn update(&mut self, rhs: Widget) {
        *self = (*self).foo(rhs)
    }
}

但编译器抱怨“无法脱离借用的上下文”。正确的方法是什么?

换一种方法:

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并不关心掉落是否是不可操作的),这尤其有问题。

用另一种方法:

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并不关心掉落是否是不可操作的)。

一个选项是使用板条箱,它提供的
take
功能完全满足您的要求:

take
允许从
&mut T T
中提取
T
,使用它做任何事情,包括消费它,并生成另一个
T
放回
&mut T T

正如所指出的,这样做的问题是,如果发生死机,
&mut
引用将处于无效状态,这可能导致未定义的行为。
take_mut
方法是:

take
期间,如果出现恐慌,整个过程将退出,因为没有有效的
T
放回
&mut T 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));
    }
}
一种选择是使用板条箱,它提供了
take
功能,可以完全满足您的需求:

take
允许从
&mut T T
中提取
T
,使用它做任何事情,包括消费它,并生成另一个
T
放回
&mut T T

正如所指出的,这样做的问题是,如果发生死机,
&mut
引用将处于无效状态,这可能导致未定义的行为。
take_mut
方法是:

take
期间,如果出现恐慌,整个过程将退出,因为没有有效的
T
放回
&mut T 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));
    }
}

假设我不能或不想这样做(考虑到这需要一个完全不同的设计,并且没有实际的理由说明另一种方法不应该同样有效),这是一个很好的观点。我没有考虑如果有恐慌会发生什么。假设我不能或不想(因为这需要一个完全不同的设计,没有实际的理由为什么另一种方式也不工作)。这是一个很好的观点。我没有想到会发生什么,如果有恐慌。