为什么这个可变借用超出了它的范围? [英] Why does this mutable borrow live beyond its scope?

查看:60
本文介绍了为什么这个可变借用超出了它的范围?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我期望可变借用结束之后,我遇到了关于同时使用可变和不可变借用的令人困惑的错误.我对类似问题做了很多研究(1234) 这让我相信我的问题与 词法生命周期(虽然打开 NLL 功能并每晚编译不会改变结果),我只是不知道是什么;我的情况似乎不适合其他问题的任何场景.

I've encountered a confusing error about the use of a mutable and immutable borrow at the same time, after I expect the mutable borrow to end. I've done a lot of research on similar questions (1, 2, 3, 4) which has led me to believe my problem has something to do with lexical lifetimes (though turning on the NLL feature and compiling on nightly doesn't change the result), I just have no idea what; my situation doesn't seem to fit into any of the scenarios of the other questions.

pub enum Chain<'a> {
    Root {
        value: String,
    },
    Child {
        parent: &'a mut Chain<'a>,
    },
}

impl Chain<'_> {
    pub fn get(&self) -> &String {
        match self {
            Chain::Root { ref value } => value,
            Chain::Child { ref parent } => parent.get(),
        }
    }

    pub fn get_mut(&mut self) -> &mut String {
        match self {
            Chain::Root { ref mut value } => value,
            Chain::Child { ref mut parent } => parent.get_mut(),
        }
    }
}

#[test]
fn test() {
    let mut root = Chain::Root { value: "foo".to_string() };

    {
        let mut child = Chain::Child { parent: &mut root };

        *child.get_mut() = "bar".to_string();
    } // I expect child's borrow to go out of scope here

    assert_eq!("bar".to_string(), *root.get());
}

游乐场

错误是:

error[E0502]: cannot borrow `root` as immutable because it is also borrowed as mutable
  --> example.rs:36:36
   |
31 |         let mut child = Chain::Child { parent: &mut root };
   |                                                --------- mutable borrow occurs here
...
36 |     assert_eq!("bar".to_string(), *root.get());
   |                                    ^^^^
   |                                    |
   |                                    immutable borrow occurs here
   |                                    mutable borrow later used here

我理解为什么在那里发生不可变借用,但我不明白在那里如何使用可变借用.如何在同一个地方使用两者?我希望有人可以解释正在发生的事情以及我如何避免它.

I understand why an immutable borrow happens there, but I do not understand how a mutable borrow is used there. How can both be used at the same place? I'm hoping someone can explain what is happening and how I can avoid it.

推荐答案

简而言之,&'a mut Chain<'a> 是极其有限和普遍的.

In short, &'a mut Chain<'a> is extremely limiting and pervasive.

对于不可变引用&T<'a>,编译器可以在必要时缩短'a的生​​命周期以匹配其他生命周期或作为其一部分NLL(这不是总是的情况,这取决于T是什么).但是,它不能为可变引用 &mut T<'a> 这样做,否则您可以为其分配一个生命周期较短的值.

For an immutable reference &T<'a>, the compiler is allowed to shorten the lifetime of 'a when necessary to match other lifetimes or as part of NLL (this is not always the case, it depends on what T is). However, it cannot do so for mutable references &mut T<'a>, otherwise you could assign it a value with a shorter lifetime.

因此,当编译器尝试协调引用和参数链接时的生命周期&'a mut T<'a>,引用的生命周期在概念上被扩展以匹配生命周期的参数.这实质上意味着您创建了一个永远不会被释放的可变借用.

So when the compiler tries to reconcile the lifetimes when the reference and the parameter are linked &'a mut T<'a>, the lifetime of the reference is conceptually expanded to match the lifetime of the parameter. Which essentially means you've created a mutable borrow that will never be released.

基本上,只有当嵌套值在其生命周期内是协变的,才能创建基于引用的层次结构.其中不包括:

Basically, creating a reference-based hierarchy is really only possible if the nested values are covariant over their lifetimes. Which excludes:

  • 可变引用
  • 特征对象
  • 具有内部可变性的结构

playground 上参考这些变体 看看它们如何不像预期的那样工作.

Refer to these variations on the playground to see how these don't quite work as expected.

另见:

这篇关于为什么这个可变借用超出了它的范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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