Skip to content

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

Description

@ZhangHanDong

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; ,为什么会报错?

Activity

  1. changed the title [-]该段代码为什么会通过?[/-] [+][Practice] 该段代码为什么会通过?[/+] on Oct 28, 2017
  2. ZhangHanDong commented on Oct 28, 2017

    @ZhangHanDong
    ContributorAuthor

    相关issue: rust-lang/rust#45587

  3. huangjj27 commented on Feb 6, 2018

    @huangjj27

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

    1. rustc推断在main中声明的map的K, 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), 所有生命周期参数得以满足, 于是通过了编译.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions