Reputation: 113
I am totally confused about lifetimes after this error:
#![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);
}
This gives me error:
<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();
But if I declare hs
later, right after zeros
and ones
, everything works fine:
#![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);
}
Output:
0000000000
1111111111
{0000000000, 1111111111}
Program ended.
You can try code here.
--
I asked this question on IRC got the following answer:
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.
Upvotes: 2
Views: 216
Reputation: 90722
The type of hs
is HashSet<&'ρ BitVec>
—but what is 'ρ
?
The error message explains it a bit:
<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();
It is saying that the reference must be legit for the rest of the block after line 7, where the HashSet
is defined.
That, then, is what 'ρ
is: the rest of the block after line 7.
Think of it this way: when the HashSet<&BitVec>
is created, would it be legitimate to immediately insert the values? No, because they are references to things that do not exist yet.
If you were inserting the BitVec
s rather than references to them, the problem would go away, for while the lifetime of &'ρ BitVec
is 'ρ
, the lifetime of BitVec
is 'static
, as it contains no non-static data, and so inserting hs.insert(BitVec::from_elem(10, false))
would be just fine.
Now why could the compiler not allow the earlier definition of hs
? When it infers the type, it must be a type that is legal where it is. If it were to infer for the lifetime “after line 13” when the hs
declaration is on line 7, you would have something that is not legal at the time of its declaration. In this particular case nothing is done with the T
of HashSet<T>
in a new
call, so you might say that theoretically the compiler could ignore the fact that it’s dealing with an illegal type that will become legal by the time we actually use it, but that would be downright evil and inconsistent (changes to the body of a function could potentially affect callers) so Rust forbids the entire class of behaviour.
Upvotes: 3