原文链接:https://doc.rust-lang.org/nomicon/lifetime-mismatch.html

生命周期的局限

考虑下面的代码:

#[derive(Debug)]
struct Foo;

impl Foo {
    fn mutate_and_share(&mut self) -> &Self {&*self}
    fn share(&self) {}
}

fn main() {
    let mut foo = Foo;
    let loan = foo.mutate_and_share();
    foo.share();
    println!("{:?}", loan);
}

你可能觉得它能成功编译。我们调用mutate_and_share,临时可变地借用foo,但接下来返回一个共享引用。因为调用foo.share()时没有可变的引用了,所以我们认为可以正常调用。

但是当我们尝试编译它:

error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
  --> src/main.rs:12:5
   |
11 |     let loan = foo.mutate_and_share();
   |                --- mutable borrow occurs here
12 |     foo.share();
   |     ^^^ immutable borrow occurs here
13 |     println!("{:?}", loan);

发生了什么呢?嗯……我们遇到了和上一章的示例2相同的错误。我们去掉语法糖,会得到这样的代码:

struct Foo;

impl Foo {
    fn mutate_and_share<'a>(&'a mut self) -> &'a Self { &'a *self }
    fn share<'a>(&'a self) {}
}

fn main() {
    'b: {
        let mut foo: Foo = Foo;
        'c: {
            let loan: &'c Foo = Foo::mutate_and_share::<'c>(&'c mut foo);
            'd: {
                Foo::share::<'d>(&'d foo);
            }
            println!("{:?}", loan);
        }
    }
}

生命周期系统强行把&mut foo的生命周期扩展到'c,以和loan的生命周期以及mutate_and_share的签名匹配。接下来我们调用share,Rust认为我们在给&'c mut foo创建别名,于是拒绝了我们。

这段程序显然完全符合引用的语义,但是我们的生命周期系统过于粗糙,无法对它进行正确的分析。

借用减少不当

以下当前无法编译,因为Rust不了解不再需要借用,因此保守地退回到使用整个作用域。这最终将得到解决。


#![allow(unused)]
fn main() {
use std::collections::HashMap;
use std::hash::Hash;
fn get_default<'m, K, V>(map: &'m mut HashMap<K, V>, key: K) -> &'m mut V
where
    K: Clone + Eq + Hash,
    V: Default,
{
    match map.get_mut(&key) {
        Some(value) => value,
        None => {
            map.insert(key.clone(), V::default());
            map.get_mut(&key).unwrap()
        }
    }
}
}