Okay, so NLL will land in Rust 1.31. So we can talk about two cases: before 1.31, and after.
Before 1.31, with the old lifetime rules. Everything goes out of scope at the end of the lexical scope it was defined in. Furthermore, things are dropped in the reverse order they're declared:
fn main() {
let mut v = Val; <- first, v
println!("First reference");
let r1 = v.reference(); <- second, r1
println!("Second reference");
let r2 = v.reference(); <- third, r2
println!("Done");
//println!("{:?}", r1.0);
} <- everything goes out of scope here, and is dropped in reverse order: r2, r1, v
Therefore, r1
and r2
both exist for the same length of time r2
exists, so you have two mutable references.
After 1.31, with "non-lexical liftimes". The rules are now "things that implement Drop go out of scope at the end of the lexical scope they're defined in. Things that don't implement Drop go out of scope at the last time they're used.
fn main() {
let mut v = Val; <- first, v
println!("First reference");
let r1 = v.reference(); <- second, r1. v is used here, so it must live this long. r1 is not used again, and so drops immediately.
println!("Second reference");
let r2 = v.reference(); <- third, r2. v is used here, so it must live this long. r2 is not used again, and so drops immediately.
<- additionally, v is never used again, and so is dropped here
println!("Done");
//println!("{:?}", r1.0);
} <- we have nothing still in scope
Now, there's two things that change this: uncommenting the println
, and the Drop
impl. If we uncomment the println:
fn main() {
let mut v = Val; <- first, v
println!("First reference");
let r1 = v.reference(); <- second, r1. v is used here, so it must live this long.
println!("Second reference");
let r2 = v.reference(); <- third, r2. v is used here, so it must live this long. r2 is not used again, and so drops immediately.
println!("Done");
println!("{:?}", r1.0); <- r1 is used here, so it must live this long
}
Now that you use r1 below, it stays alive longer, and now comes into conflict with r2
being created. Error!
With Drop
for Ref
:
fn main() {
let mut v = Val; <- first, v
println!("First reference");
let r1 = v.reference(); let r1 = v.reference(); <- second, r1. v is used here, so it must live this long. r1 implements `Drop`, and so will go out of scope at the end of `main`
println!("Second reference");
let r2 = v.reference(); <- third, r2. v is used here, so it must live this long. r2 implements `Drop`, and so will go out of scope at the end of `main`
println!("Done");
// println!("{:?}", r1.0);
} <- r2 would drop, then r1
This also makes r1
live long enough to come into conflict with r2
.
Does that clear it up?