返回传递给函数的不可变引用后面的可变引用 [英] Returning a mutable reference that is behind an immutable reference, passed to the function

查看:100
本文介绍了返回传递给函数的不可变引用后面的可变引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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感到困惑.

I (sort of) understand what the compiler is trying to prevent here. But I am confused with the error message assignment into an immutable reference . What exactly is being assigned into self (or inside ofself.f?) ?

我编写了以下代码来模拟此问题,并得到了相同的错误消息,与上面的代码不同,我能够理解.这是代码:

I wrote the following code to simulate this problem and got the same error message, which unlike the above one, I am able to understand. Here's the code:

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
}

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

In the first example, is it trying to move the mutable reference f out of self (since &mut is not a Copy type), treating it as a mutation inside the immutable reference self, hence the error message assignment into an immutable reference?

推荐答案

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

You can't create a mutable reference from an immutable one. This means that you need to change &self into &mut self:

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

现在您的变量需要可变,以便您可以对该方法进行可变引用:

And now the your variable needs to be mutable so that you can take a mutable reference to it for the method:

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

到底是什么被分配给self(或在self.x内部?)?

该错误消息可能有点偏离.您的代码中没有分配,但是您返回的是 mutable 引用.可变引用唯一可以让您在这里做的事情就是分配self.fself.f.i.

The error message might be a little off. There is no assignment in your code, but you are returning a mutable reference. The only extra thing that a mutable reference would let you do here is to assign self.f or self.f.i.

绝对可以改善此错误消息,但确实包含使&'a self可变以解决问题的提示.

Definitely this error message can be improved, but it does include a hint to make the &'a self mutable to fix the problem.

现在,您的原始问题:

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

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

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

Rust provides a variety of container types for interior mutability, such as Cell and RefCell. These types take the responsibility for ensuring correctness away from the compiler and make it a runtime check. One way of applying a RefCell to your code might be like this:

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;
}

这篇关于返回传递给函数的不可变引用后面的可变引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆