reference - 返回传递给函数的不可变引用后面的可变引用

标签 reference rust immutability mutable

如何返回不可变引用后面的可变引用,作为参数传递给函数,如何处理?

struct Foo { i: i32 }

struct Bar<'b> {
    f: &'b mut Foo
}

impl<'a: 'b, 'b> Bar<'b> {
    fn func(&'a self) -> &'b mut Foo {
         self.f
    }
}

fn main() {
    let mut foo = Foo { i: 1 };

    let bar = Bar { f: &mut foo };
    bar.func(); 
}

出现以下错误:

error[E0389]: cannot borrow data mutably in a `&` reference
 --> src/main.rs:9:14
  |
8 |         fn func(&'a self) -> &'b mut Foo {
  |                 -------- use `&'a mut self` here to make mutable
9 |              self.f
  |              ^^^^^^ assignment into an immutable reference

我(有点)理解编译器在这里试图阻止什么。但是我对错误消息 assignment into an immutable reference 感到困惑。 self(或 self.f 内部)究竟分配了什么?

我写了下面的代码来模拟这个问题,得到了同样的错误信息,和上面的不同,我能理解。这是代码:

fn main() {
    let mut foo = Foo { i: 1 };

    let bar = Bar { f: &mut foo };
    let pbar = &bar;

    pbar.f.i = 2; // assignment into an immutable reference
}

在第一个示例中,它是否试图将可变引用 f 移出 self(因为 &mut 不是 Copy 类型),将其视为不可变引用 self 内的突变,因此出现错误消息 assignment into an immutable reference?

最佳答案

您不能从不可变引用创建可变引用。这意味着您需要将 &self 更改为 &mut self:

impl<'a: 'b, 'b> Bar<'b> {
    fn func(&'a mut self) -> &'b mut Foo {
         self.f
    }
}

现在您的变量需要是可变的,以便您可以为方法获取对它的可变引用:

let mut bar = Bar { f: &mut foo };
bar.func(); 

What exactly is being assigned into self (or inside of self.x?) ?

错误信息可能有点不对劲。您的代码中没有赋值,但您返回了一个可变 引用。可变引用允许您在这里做的唯一额外的事情是分配 self.fself.f.i

当然可以改进此错误消息,但它确实包含使 &'a self 可变以解决问题的提示。

现在,您的原始问题:

How is returning a mutable reference that is behind an immutable reference, passed as an argument to the function, handled?

Rust 为内部可变性提供了多种容器类型,例如 CellRefCell。这些类型负责确保编译器的正确性,并使其成为运行时检查。将 RefCell 应用于您的代码的一种方法可能是这样的:

use std::cell::RefCell;
use std::ops::DerefMut;

struct Foo { i: i32 }

struct Bar<'b> {
    // store the data in a RefCell for interior mutability
    f: &'b RefCell<Foo>
}

impl<'a: 'b, 'b> Bar<'b> {
    // Return a RefMut smart pointer instead of mutable ref, but hide the implementation,
    // just exposing it as something that can be mutably dereferenced as a Foo
    fn func(&'a self) -> impl DerefMut<Target = Foo> + 'b {
         self.f.borrow_mut()
    }
}

fn main() {
    let foo = RefCell::new(Foo { i: 1 });
    let bar = Bar { f: &foo };

    let mut f = bar.func(); 
    f.i = 3;
}

关于reference - 返回传递给函数的不可变引用后面的可变引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52197812/

相关文章:

reference - 如何使用 DBRef 查询 mongodb

closures - 将修改其环境的闭包传递给 Rust 中的函数

string - 如何将字符串分配给可变静态变量?

c# - 实现 ICloneable 接口(interface) C#(深度克隆)

c++ - 有没有办法在 C++ 中预先声明嵌套类?

Emacs Racer "can' t 找到箱子”

java - 为什么这段java代码没有产生我期望的结果?

.net - 如何将 NHibernate 与 System.Tuple 等不可变类型一起使用?

c# - ImmutableArray如何正确使用

python - Python 中的引用和值传递