代码之家  ›  专栏  ›  技术社区  ›  rmeador

借用范围之外的生命

  •  0
  • rmeador  · 技术社区  · 4 年前

    1 2 , 3 4 , 5 )这让我相信我的问题与 lexical lifetimes (虽然打开NLL功能并在夜间编译不会改变结果),但我不知道会发生什么;我的情况似乎不符合其他问题的任何情况。

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

    playground

    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
    

    我理解为什么不可变借用会发生在那里,但我不理解可变借用是如何在那里使用的。如何在同一个地方使用这两种方法?我希望有人能解释发生了什么以及我如何避免它。

    0 回复  |  直到 3 年前
        1
  •  8
  •   kmdreko    4 年前

    &'a mut Chain<'a> 这是非常有限和普遍的。

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

    &'a mut T<'a>

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

    • 特征对象
    • 内部可变结构

    请参阅上的这些变体 playground

    另见:

        2
  •  3
  •   Aiden4    4 年前

    问题不是词法生命周期,而是添加显式 drop &'a mut Chain<'a> -这迫使 root 在其整个生命周期内被借用,在借用被放弃后使其无用。根据下面的评论,在生命周期内这样做基本上是不可能的。我建议用盒子代替。将结构更改为

    pub enum Chain{
    Root {
            value: String,
        },
        Child {
            parent: Box<Chain>,
        },
    }
    

    并根据需要调整其他方法。或者,使用 Rc<RefCell<Chain>> 如果你想让原作在不消耗自我的情况下保持可用性。