如果在我插入的数据之后声明,则无法在 HashMap 中插入引用

Cannot insert reference in HashMap if it is declared after the data I am inserting

发生这个错误后,我对生命周期感到非常困惑:

#![feature(collections)]
use std::collections::BitVec;
use std::collections::HashSet;

fn main() {
    let mut hs = HashSet::new();

    let  zeros :  BitVec = BitVec::from_elem(10,false);
    let  ones  :  BitVec = BitVec::from_elem(10,true);    
    println!("{:?}\n{:?}",zeros,ones);
    // let mut hs = HashSet::new(); // works only if move this line to #7

    hs.insert(&zeros);
    hs.insert(&ones);
    println!("{:?}",hs);
}

这给我错误:

<anon>:14:16: 14:21 error: `zeros` does not live long enough
<anon>:14     hs.insert(&zeros);
                         ^~~~~
<anon>:7:33: 17:2 note: reference must be valid for the block suffix following statement 0 at 7:32...
<anon>:7     let mut hs = HashSet::new();

但是如果我稍后声明 hs,就在 zerosones 之后,一切正常:

#![feature(collections)]
use std::collections::BitVec;
use std::collections::HashSet;

fn main() {
    // let mut hs = HashSet::new();

    let  zeros :  BitVec = BitVec::from_elem(10,false);
    let  ones  :  BitVec = BitVec::from_elem(10,true);    
    println!("{:?}\n{:?}",zeros,ones);
    let mut hs = HashSet::new(); // works only if move this line to #7

    hs.insert(&zeros);
    hs.insert(&ones);
    println!("{:?}",hs);
}

输出:

0000000000
1111111111
{0000000000, 1111111111}
Program ended.

您可以尝试代码 here

--

我在 IRC 上问了这个问题得到了以下答案:

talchas: basically objects are destroyed line by line (well, statement by statement) in reverse order they were created,so if the bitsets were destroyed before the hashset, then the hashset's destructor would run with invalid pointers in it. if you declare them afterwards they get destroyed before the hashset does and you have references to them in the hashset.

so for this in particular, there's https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md and probably some discussion in pull requests and such

reem: The RFC that introduced it goes into great detail https://github.com/rust-lang/rfcs/blob/f78aa94fd44c890ef5091a646db4d4159d21e1e2/text/0000-sound-generic-drop.md, but might not be the best thing to read to just get a quick understand.

hs的类型是HashSet<&'ρ BitVec>——但是是什么?

错误信息稍微解释了一下:

<anon>:7:33: 17:2 note: reference must be valid for the block suffix following statement 0 at 7:32...
<anon>:7     let mut hs = HashSet::new();

意思是对于第 7 行之后的块的其余部分,引用必须是合法的,其中定义了 HashSet

那就是 的内容:第 7 行之后的剩余部分。

这样想:创建 HashSet<&BitVec> 后,立即 插入值是否合法?不,因为它们是对尚不存在的事物的引用。

如果您插入 BitVec 而不是对它们的引用,问题就会消失,因为 &'ρ BitVec 的生命周期是 BitVec'static,因为它不包含非静态数据,因此插入 hs.insert(BitVec::from_elem(10, false)) 就可以了。

现在为什么编译器不允许 hs 的早期定义?当它推断类型时,它必须是合法的类型。如果要在 hs 声明位于第 7 行时推断“第 13 行之后”的生命周期,那么在其声明时你会得到一些不合法的东西。在这种特殊情况下,在 new 调用中 HashSet<T>T 没有做任何事情,所以你可能会说理论上编译器可以忽略它正在处理非法类型的事实在我们实际使用它时变得合法,但这将是彻头彻尾的邪恶和不一致(对函数主体的更改可能会影响调用者)因此 Rust 禁止整个 class 行为。