rust_interview icon indicating copy to clipboard operation
rust_interview copied to clipboard

[Practice] 该段代码为什么会通过?

Open ZhangHanDong opened this issue 8 years ago • 2 comments
trafficstars

Rust Nightly 1.22.0

use std::collections::BTreeMap;

fn foo(_qux: &BTreeMap<&'static str, &'static str>) -> Option<String> {
    Some("baz".to_owned())
}

fn main() {
    let mut map = BTreeMap::new();
    map.insert("foo", "bar");
    foo(&map).and_then( |baz| {
        let mut map = map;
        map.insert("sign", &baz);
        Some(())
    });
}

如果注释掉 let mut map = map; ,为什么会报错?

ZhangHanDong avatar Oct 28 '17 08:10 ZhangHanDong

相关issue: https://github.com/rust-lang/rust/issues/45587

ZhangHanDong avatar Oct 28 '17 08:10 ZhangHanDong

当去掉let语句之后产生了如下的语义:

  1. rustc推断在main中声明的mapK, V是具有'static lifetime, 理由是foo函数接受了map作为参数;
  2. foo返回的Some是to_owned的关系, 所以变量baz会被move到闭包之中, 于是其析构也会提前到闭包调用结束, baz的生命周期为整个闭包调用

因此baz的声明周期没有'static长, 所以报错:

 error[E0597]: `baz` does not live long enough
  --> test.rs:12:29
   |
12 |         map.insert("sign", &baz);
   |                             ^^^ borrowed value does not live long enough
13 |         Some(())
14 |     });
   |     - borrowed value only lives until here
   |
   = note: borrowed value must be valid for the static lifetime...

而当我们保留了let语句是, 相当于把mapmove到了闭包中, 并且在let语句的时候重新推断了生命周期条件:

// let dist_map: BTreeMap(&'static str, &'a str) = moved_map;
let map = map;

而这种推断是合理的, 因为'static生命周期要比任何生命周期'a'要长('static: 'a);

接着, rust再推断出满足'a lifetime的最小lifetime 要比&baz的lifetime要长('a: 'baz), 所有生命周期参数得以满足, 于是通过了编译.

huangjj27 avatar Feb 06 '18 15:02 huangjj27