可变借用似乎超出了它的范围 [英] Mutable borrow seems to outlive its scope

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

问题描述

尝试编译这个程序时,我在借用检查器上卡住了:

Trying to compile this program I get stuck on the borrow checker:

use std::collections::BTreeMap;

type Object<'a> = BTreeMap<&'a str, i32>;

struct Root<'a>(Object<'a>);

struct Sub<'a>(&'a mut Object<'a>, &'a str);

impl<'a> Root<'a> {
    fn borrow_mut(&'a mut self, data: &'a str) -> Sub<'a> {
        Sub(&mut self.0, data)
    }

    fn borrow(&self) {
        println!("{:?}", self.0);
    }
}

fn main() {
    let mut me = Root(Object::new());
    {
        me.borrow_mut("data!");
    }
    me.borrow();
}

(游乐场)

我明白了:

error[E0502]: cannot borrow `me` as immutable because it is also borrowed as mutable
  --> src/main.rs:24:5
   |
22 |         me.borrow_mut("data!");
   |         -- mutable borrow occurs here
23 |     }
24 |     me.borrow();
   |     ^^ immutable borrow occurs here
25 | }
   | - mutable borrow ends here

看起来可变借用应该在 me.borrow() 之前结束,但借用检查器坚持它在 main 结束时结束.

It looks like the mutable borrow should end before me.borrow() but the borrow checker insists that it ends when main ends.

快速说明我要完成的任务:

To quickly explain what I'm trying to accomplish:

  1. 创建一个父结构来保存数据
  2. 制作数据的子类别并将其存储在父类别中
  3. 使用此构建器样式模式进行 MongoDB 查询

推荐答案

您遇到了终生问题.

您的程序中有多个不同的生命周期:

There are multiple different lifetimes in your program:

  • type Object<'a>= BTreeMap<&'a str, i32>; => 这是一个
  • &'a mut Object<'a> => 这里最多有两个
  • struct Sub<'a>(&'a mut Object<'a>, &'a str); => 这里最多三个
  • type Object<'a> = BTreeMap<&'a str, i32>; => this is one
  • &'a mut Object<'a> => there are up to TWO here
  • struct Sub<'a>(&'a mut Object<'a>, &'a str); => there are up to THREE here

显然,对 Object<'a> 的引用没有理由与 BTreeMap<中的 &str 具有相同的生命周期/代码>.但是,您告诉编译器您希望两个生命周期相同!

There is, apparently, no reason for the reference to Object<'a> to have the same lifetime than the &str inside the BTreeMap. However, you told the compiler that you wanted both lifetimes to be the same!

当你写作时:

struct Sub<'a>(&'a mut Object<'a>, &'a str);

你告诉编译器:

  • BTreeMap&str 的生命周期
  • 引用Object<'_>
  • 的生命周期
  • 伴随Object<'_>
  • &str的生​​命周期
  • the lifetime of the &str inside BTreeMap
  • the lifetime of the reference to Object<'_>
  • the lifetime of the &str accompanying the Object<'_>

都是一回事.

您过度限制了要求;因此,没有任何解决方案可以满足他们.

You have over-constrained the requirements; and as a result no solution can satisfy them.

再增加一个自由度就足够了!我们只会让 Object<'_> 的引用的生命周期与那些浮动的 &str 的生命周期不同:

Adding one more degree of freedom is sufficient! We'll just make the lifetime of the reference to Object<'_> different from the lifetime of those &str floating around:

struct Sub<'a, 'b: 'a>(&'a mut Object<'b>, &'b str);

impl<'b> Root<'b> {
    fn borrow_mut<'a>(&'a mut self, data: &'b str) -> Sub<'a, 'b> {
        Sub(&mut self.0, data)
    }

    fn borrow(&self) {
        println!("{:?}", self.0);
    }
}

注意微妙的 'b: 'a:

  • Object<'b> 包含对生命周期为 'b
  • 的引用
  • Object<'b>(用'a表示)的引用的生命周期必须比'b短(否则你有对死亡事物的引用?)
  • Object<'b> contains a reference to something whose lifetime is 'b
  • the lifetime of the reference to Object<'b> (denoted 'a) must be SHORTER than 'b (otherwise you have a reference to something dead?)

因此,我们说 'b'a 寿命长,'b:'a.

Thus, we say that 'b outlives 'a with 'b: 'a.

就是这样.只需放宽要求,编译器就可以编译您的代码.

And that's it. Simply loosening the requirements allow the compiler to allow your code to compile.

请注意,一般来说,如果您发现自己编写了类似 &'a &'a str 的内容,那么您就错了.如果你仔细想想,你会意识到为了创建对某物的引用,它必须首先be.因此,对对象的引用必然比对象本身具有更短的生命周期(稍微短一些).

Note that in general, if you find yourself writing something like &'a &'a str you are doing it wrong. If you think about it, you will realize that in order to create a reference to something, it must first be. And therefore a reference to an object necessarily has a shorter lifetime than the object itself (ever so slightly).

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

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