I'm trying to figure out a Rust lifetime issue and after boiling it down a bunch, I realized that I have no idea how I would explicitly annotate the lifetimes of r, x2, and _arr in foo:
struct X<'a> {
_v: &'a mut i32,
}
fn main() {
let mut v1 = 0;
let x1 = X { _v: &mut v1 };
foo(x1);
}
fn foo(x1: X) {
let mut v2 = 1;
let r = &mut v2;
let x2 = X { _v: r };
let _arr = [x1, x2];
}
I'm going to work off of the assumption that the part of your code that got cut off is the following:
struct X<'a> {
_v: &'a mut i32,
}
In that case, let's dissect what's going on in foo a little bit.
fn foo(x1: X) {
// Lives until the end of the function, call its lifetime 'v2
let mut v2 = 1;
// Borrow v2 for some lifetime 'r which is no longer than 'v2
// so r is of type &'r mut i32
let r = &mut v2;
let x2 = X { _v: r }; // x2 is of type X<'r>
let _arr = [x1, x2]; // ??
}
The confusion probably comes from the fact that x1 seems to have an ambiguous lifetime in its type. This is because we didn't explicitly specify the lifetime in x1: X. This is a Rust 2018 idiom, and I personally recommend not doing this. You can add #![deny(rust_2018_idioms)] to the top of your crate root and the compiler will point out these ambiguities to you and force you to be more explicit. What happens here is that the function declaration gets de-sugared to the following:
fn foo<'x1>(x1: X<'x1>) { ... }
Now it is implied that the lifetime 'x1 extends at least through the body of foo, and this makes sense because it kind of has to. If something which lived for 'x1 was freed in the middle of foo (disregarding how something like that could even happen), then that would defeat the point of using lifetimes for memory safety.
So that being said, let's revisit this line:
let _arr = [x1, x2];
We know that x2 is of the type X<'r> and that 'r extends at most to the end of foo (since 'r is no longer than 'v2 and 'v2 extends to the end of foo). Moreover, we know that x1 is of the type X<'x1> and that 'x1 extends at least to the end of foo. This means that 'x1 is at least as long as 'r. Since lifetimes are covariant, this means that X<'x1> is a sub-type of X<'r>, since whenever we require a value of the type X<'r> we can safely substitute in one of type X<'x1> instead. So what happens is _arr is given the type [X<'r>; 2], and upon construction the lifetime on x1 is shortened to 'r.
We can actually test this hypothesis to see if it's correct. What would happen if the compiler wasn't allowed to shorten that lifetime? In other words, what if the lifetime on X was not covariant. If we modify X as follows then its lifetime type parameter is made invariant:
struct X<'a> {
_v: &'a mut i32,
_invariant: PhantomData<fn(&'a ()) -> &'a ()>
}
And sure enough, after adding the _invariant field in the appropriate places to make the code compile, we receive the following error:
|
14 | fn foo<'x1>(x1: X<'x1>) {
| --- lifetime `'x1` defined here
15 | let mut v2 = 1;
16 | let r = &mut v2;
| ^^^^^^^ borrowed value does not live long enough
17 | let x2 = X { _v: r, _invariant: PhantomData };
| - this usage requires that `v2` is borrowed for `'x1`
18 | let _arr = [x1, x2];
19 | }
| - `v2` dropped here while still borrowed
Now how do we know the compiler wasn't extending the lifetime 'r to 'x1 in the first place? Well if it was doing that, then we could modify foo to do the following, which would unequivocally cause a use-after-free:
fn foo<'x1>(x1: X<'x1>) -> &'x1 mut i32 {
let mut v2 = 1;
let r = &mut v2;
let x2 = X { _v: r };
let _arr = [x1, x2];
_arr[1]._v
}
And sure enough if you try the code above it fails to compile with the reason given being that we're returning a reference to a local variable. Moreover, if you try returning _arr[0]._v, then you get the exact same error.
Sub-typing and variance can be pretty hard to grasp and it's not something you need to fully understand to be an effective Rust programmer. Nonetheless, it is very interesting and you can learn more about it here in the Rustonomicon.
Related
fn main() {
struct Foo<'a, T> {
a: &'a mut T,
}
let p1 = 1;
let mut p2 = &p1;
{
let p3 = 2;
let mut p4 = &p3;
let mut f = Foo {
a: &mut p4,
};
f.a = &mut p2;
println!("{}", f.a);
}
println!("{}", p2);
}
While run this program, it meets error such as:
error[E0597]: `p3` does not live long enough
--> src/main.rs:10:19
|
10 | let mut p4 = &p3;
| ^^^ borrowed value does not live long enough
...
16 | }
| - `p3` dropped here while still borrowed
17 | println!("{}", p2);
| -- borrow later used here
-- borrow later used here
this is my first question: why exist these errors?
If I annotate the last line, such as :
fn main() {
struct Foo<'a, T> {
a: &'a mut T,
}
let p1 = 1;
let mut p2 = &p1;
{
let p3 = 2;
let mut p4 = &p3;
let mut f = Foo {
a: &mut p4,
};
f.a = &mut p2;
println!("{}", f.a);
}
// println!("{}", p2);
}
It runs successfully. By refer to rustonomicon,
f.a = &mut p2;
&'a mut T is covariant over 'a and invariant over T, It should compile unsuccesfully. But successfully, why?
If I annotate the last line, It should compile unsuccesfully.
The core of the problem is that f has a single fixed type Foo<'a, &'b i32> and by the variance rules for mutable references, &'b i32 is invariant and thus 'b is invariant.
However, f is used with T as two separate lifetimes via p2 and p4. How does the compiler choose? Well it cannot shorten the lifetime used by p2 into that of p4, because then p2 can be modified to reference something of a smaller lifetime and thus p2 can dangle at the last println! (consider what would happen if you added *f.a = &p3; right after assigning f.a to &mut p2). The only option is for the lifetime used by p4 to be widened to match p2.
Since p4 must match the lifetime of p2, the assignment from p3 is now too short, so you get the error you see.
The second example works because the lifetime used by p2 does not extend after the println! in the inner block, so p3 can satisfy that lifetime.
I'm having some trouble understanding the compiler error message for this code:
struct A {
b: B,
c: C,
}
struct B {
f: u32,
}
struct C {
f: u32,
}
fn foo(b: &mut B) -> &u32 { &b.f }
fn bar(c: &mut C) -> &u32 { &c.f }
fn quux(z: &mut A) -> u32 { z.b.f }
fn baz(a: &mut A) {
let x = foo(&mut a.b);
let y = bar(&mut a.c);
let z = quux(a); // equivalent to: quux(&mut *a)
println!("{} {}", x, y);
}
error[E0499]: cannot borrow `*a` as mutable more than once at a time
--> src/main.rs:22:18
|
20 | let x = foo(&mut a.b);
| -------- first mutable borrow occurs here
21 | let y = bar(&mut a.c);
22 | let z = quux(a);
| ^ second mutable borrow occurs here
23 | println!("{} {}", x, y);
| - first borrow later used here
For more information about this error, try `rustc --explain E0499`.
error: could not compile `playground` due to previous error
If line 20 is mutably borrowing *a (as the compilation error asserts), then line 21 must also mutably borrow *a (How couldn't it? It's nearly identical to line 20 -- only difference is which field is borrowed), so by my reasoning the code should still fail to compile after deleting line 22; however, the code actually compiles just fine if I delete line 22. The fact that this would then compile seems to contradict the compiler's claim that &mut a.b results in a mutable borrow of *a.
x and y are immutable borrows, so if anything I would expect a compilation error regarding the overlapping scopes of the immutable x/y and the mutable borrow of *a in line 22 (otherwise quux could conceivably mutate a while we're borrowing its fields).
What knowledge am I likely missing that makes this error message confusing to me? If you're not surprised by this message, could you break down how you reason about this?
Some more thinking before I submitted this question:
I suppose the immutable references returned from foo and bar somehow extend the original mutable borrows of a.b and a.c (why that would be necessary, I don't know). If that's the case, maybe the way to see this is that &mut a.b and &mut a.c in turn extend the mutable borrow of *a. The error message says the first mutable borrow of *a occurs on line 20, but maybe the way to see this is:
The true first borrow of *a is when when the caller gives us the &mut A.
While the compiler suggests there's a mutable borrow of *a on line 20, this isn't exactly the case: the mut &a.b expression borrows (*a).b, but merely extends the existing borrow given to us (as opposed to being a new mutable borrow of *a).
The last point, but with respect to mut &a.c.
Insert the aforementioned reasoning of "extending borrows" wrt *a.
The call to quux then mutably borrows the *a a second time.
So maybe what the compilation error calls the initial borrow of *a is actually reporting the location of the expression responsible for extending the original *a borrow?
Line 20 does not conflict with 21 since they borrow different fields within a and therefore cause no collision.
The issue is that foo and bar return references that inherit the lifetime of the mutable reference. Even though they return immutable references, their lifetimes rely on the lifetime of the mutable borrow. So by requiring they live for a period of time, by extension the mutable borrow must do so as well. The compiler always takes the function signature on face value so it can not downgrade the initial mutable reference. If it did not, it could lead to issues if the function was modified later or if it contained unsafe code that relied on consuming a mutable reference for safety.
Here is a counter example where all of the function signatures remain the same. Since the compiler can not make assumptions on how quux and foo will use their values quux may make the references returned by foo or bar invalid.
struct A {
b: B,
c: C,
}
struct B {
f: Option<u32>,
}
struct C {
f: u32,
}
fn foo(b: &mut B) -> &u32 {
b.f.as_ref().unwrap()
}
fn bar(c: &mut C) -> &u32 { &c.f }
fn quux(z: &mut A) -> u32 {
z.b.f = None;
z.c.f
}
fn baz(a: &mut A) {
let x = foo(&mut a.b);
let y = bar(&mut a.c);
let z = quux(a);
println!("{} {}", x, y);
}
There are two issues here. First: why does let x = foo(&mut a.b); prevent you from doing let z = quux(a);, and second why does let x = foo(&mut a.b); not prevent you from doing let y = bar(&mut a.c);?
Why does let x = foo(&mut a.b); prevent you from doing let z = quux(a);?
This is due to the lifetime elision rules. You declared foo as:
fn foo(b: &mut B) -> &u32
Since you use references there must be a lifetime, but since you didn't specify one yourself the compiler assumes that all references have the same lifetime. In other words, the compiler rewrites your code as:
fn foo<'a>(b: &'a mut B) -> &'a u32
Which means that the returned value has the same lifetime as the mutable borrow, so the mutable borrow lasts until the println where you use the return value x, which prevents other borrows of a.b or a as a whole.
But then why does let x = foo(&mut a.b); not prevent you from doing let y = bar(&mut a.c);?
That's because the compiler is smart enough to realize that a.b and a.c are disjoint parts of a, which can be borrowed without conflict (in the same way that you can borrow different local variables simultaneously).
I am attempting to generate a Vec<(Point, f64)>:
let grid_size = 5;
let points_in_grid = (0..grid_size).flat_map(|x| {
(0..grid_size)
.map(|y| Point::new(f64::from(x), f64::from(y)))
.collect::<Vec<Point>>()
});
let origin = Point::origin();
let points_and_distances = points_in_grid
.map(|point| (point, point.distance_to(&origin)))
.collect::<Vec<(Point, f64)>>();
I get the following error:
use of moved value: point
I understand that I cannot use point in both elements of the tuple, but when I attempt to store a reference, I get an error regarding lifetime.
I am presuming your Point struct looks like the following:
#[derive(Debug)]
struct Point(f64, f64);
impl Point {
fn new(x: f64, y: f64) -> Self { Point(x, y) }
fn origin() -> Self { Point(0.,0.) }
fn distance_to(&self, other: &Point) -> f64 {
((other.0 - self.0).powi(2) + (other.1 - self.1).powi(2)).sqrt()
}
}
Now let's look at an even simpler example that will not compile:
let x = Point::new(2.5, 1.0);
let y = x;
let d = x.distance_to(&y);
Which gives the error:
error[E0382]: use of moved value: `x`
--> <anon>:15:13
|
14 | let y = x;
| - value moved here
15 | let d = x.distance_to(&y);
| ^ value used here after move
|
= note: move occurs because `x` has type `Point`, which does not implement the `Copy` trait
Because x has been moved into y, it now can't have a reference taken in order to call the distance_to function.
The important thing to note here is that order matters - if we swap the lines over we can call distance_to by borrowing x, the borrow will end and then x can be moved into y.
let x = Point(0., 0.);
let d = x.distance_to(&y);
let y = x; // compiles
In your case, a very similar thing is happening when constructing the tuple. point gets moved into the tuple, and then tries to borrow it to form the second element. The simplest solution is to do the same thing as here: swap the order of the elements of the tuple.
let points_and_distances = points_in_grid
.map(|point| (point.distance_to(&origin), point))
.collect::<Vec<(f64, Point)>>(); // compiles
Playground link
N.B. if you want to retain the order:
.map(|(a, b)| (b, a))
I am learning Rust and I've run into some confusing behaviour. The following code compiles fine and works as expected (edit: added code other than test function, previously omitted):
struct Container<'a> {
contents : &'a mut i32,
}
fn main() {
let mut one = Container { contents: &mut 5 };
test(&mut one);
println!("Contents: {}",one.contents);
}
fn test<'a>(mut x : &'a mut Container) {
*x.contents += 1;
let y = x;
*y.contents += 1;
x = y;
println!("{:?}",*x.contents)
}
Now in the statement
let y = x;
the type is inferred. Because x is of type &'a mut Container, I thought that this would be equivalent:
let y: &'a mut Container = x;
But when I do that, the compiler takes issue:
test_3.rs:25:5: 25:10 error: cannot assign to `x` because it is borrowed
test_3.rs:25 x = y;
^~~~~
test_3.rs:23:33: 23:34 note: borrow of `x` occurs here
test_3.rs:23 let y: &'a mut Container = x;
How is x not borrowed by that point in the correctly working example? I tested by omitting the line x = y; from the correctly working version and the compiler said:
test_3.rs:24:13: 24:14 note: `x` moved here because it has type `&mut Container<'_>`, which is moved by default
So I'm getting a move when I don't explicitly define the type but a borrow otherwise. What is going on, how do I get the same behavior as before while explicitly giving the type, and what is causing move behavior in one case but borrow in the other?
Edited with full program
When you do
let y = x;
a move happens. x is emptied, so to speak, and ownership is transferred to y.
When you do either of
let y: &mut _ = x;
let y: &'a mut _ = x;
x is reborrowed to aid matching the lifetimes. This roughly translates to
let y: &mut _ = &mut *x;
let y: &'a mut _ = &mut *x;
This leaves x non-empty, holding an aliased mutable borrow. Assigning to it thus must wait for y to be destroyed. Alternatively, you can pre-move it
let tmp = x;
let y: &'a mut _ = tmp;
I'll admit it's nonobvious behaviour, and it's a shame that you can't borrow the contents of a value without borrowing the whole value.
Why does this work
#[derive(Debug)]
pub struct Foo<'a,'b> {
s : &'a str,
n : &'b i32
}
#[test]
fn test_struct() {
let f = Foo { s : &"bar" , n : &17 };
println!("{:?}",f);
}
but this doesn't
#[derive(Debug)]
pub enum Bar<'a,'b> {
Baz ( &'a str),
Fub ( &'b i32)
}
#[test]
fn test_struct() {
let b = Bar::Baz(&"Foo");
let c = Bar::Fub(&17);
println!("{:?} {:?}",b,c);
}
The error is (part of a bigger file so ignore line numbers)
src\lib.rs:176:27: 176:29 error: borrowed value does not live long enough
src\lib.rs:176 let c = Bar::Fub(&17);
^~~~~~~~~~~~~~~~~~~~~~
To me it seems like let c = Bar::Fub(&17), the 17 lasts the same life time as the previous line where "Foo" is created on the stack. If I modify it slightly and do
let h = &17;
let c = Bar::Fub(&h);
In which case it's completely clear that h lasts longer than Bar::Fub(). SoI'm not sure how I can can get this to work.
This is a follow up to Lifetime parameters for an enum within a struct
To me it seems like let c = Bar::Fub(&17), the 17 lasts the same life time as the previous line where "Foo" is created on the stack
A string literal always has 'static lifetime and will therefor always live long enough.
I think the issue is that you are hitting is the fact that an enum expression is actually somewhat of a a function call. Somewhat meaning that the lifetime of the argument is ignored in the computation of the Enum's lifetime. The Enum's lifetime apparently is marginally larger, as if you wrote:
let c: Bar;
let x = &17;
c = Bar::Fub(x);
which is already addressed in Scope of addresses: Does not live long enough
In which case it's completely clear that h lasts longer than Bar::Fub().
Yes, the lifetimes are clear here, and it works in the Playpen:
let x = &17;
let c = Bar::Fub(x);
so I'm not sure what you are asking.