How to resolve lifetime error for mutable reference in Rust? - rust

I am not sure why the following code does not compile.
use std::cmp::Ordering;
struct MyItr<'a> {
cur: &'a i32,
}
impl<'a> Ord for MyItr<'a> {
fn cmp(&self, other: &MyItr) -> Ordering {
self.cur.cmp(&other.cur)
}
}
impl<'a> PartialOrd for MyItr<'a> {
fn partial_cmp(&self, other: &MyItr<'a>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'a> PartialEq for MyItr<'a> {
fn eq(&self, other: &MyItr) -> bool {
self.cur == other.cur
}
}
impl<'a> Eq for MyItr<'a> {}
fn f0<'a>(t0: &'a mut MyItr<'a>, t1: &'a mut MyItr<'a>, i: &'a i32) {
let t = std::cmp::max(t0, t1);
t.cur = i;
}
fn f1() {
let i0 = 1;
let i1 = 2;
let mut z0 = MyItr { cur: &i0 };
let mut z1 = MyItr { cur: &i1 };
let i2 = 3;
f0(&mut z0, &mut z1, &i2);
}
$ cargo build
Compiling foo v0.1.0 (file:///private/tmp/foo)
error: `z1` does not live long enough
--> lib.rs:40:1
|
39 | f0(&mut z0, &mut z1, &i2);
| -- borrow occurs here
40 | }
| ^ `z1` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
My understanding is the borrowed references to z0 and z1 are backed once the f0 invocation ends. However, The compiler seems to assume the borrowed references are not backed.
$ cargo --version
cargo 0.20.0-nightly (41e490480 2017-05-16)

There are two problems here. The first is that you've over-specified lifetimes, creating a situation the compiler just can't deal with.
fn f0<'a>(t0: &'a mut MyItr<'a>, t1: &'a mut MyItr<'a>, i: &'a i32)
You've told the compiler that all the arguments must be pointers with the same lifetime. The compiler can narrow overlapping lifetimes, but in this case that doesn't help. You've specified that the pointer to the MyItrs has the same lifetime as the thing they point to, and the outer pointers are mutable.
The second problem is that (even after fixing that), what you're trying to do is just outright unsafe and will lead to dangling pointers.
Here's a more minimal example:
struct S<'a> {
ptr: &'a i32,
}
fn f<'b>(t: &'b mut S<'b>, new_ptr: &'b i32) {}
fn main() {
let i0 = 1;
let mut s = S { ptr: &i0 };
let i1 = 2;
f(&mut s, &i1);
}
What is 'b? Well, the compiler can only narrow lifetimes, so usually you'd just take the lifetimes of everything you're trying to pass and pick the shortest one. In this case, that would be the lifetime of i1. So, it has to narrow the lifetime of &s. The lifetime on the pointer to s itself isn't a problem (you can narrow how long you take a borrow for), but narrowing the inner lifetime (the one used for the ptr field) is a problem.
If the compiler narrowed the lifetime of s.ptr, you would then be able to store &i1 in that field. s expects s.ptr to outlive itself, but that will no longer be true: i1 will be destroyed before s is, meaning s.ptr will contain a dangling pointer. And Rust will not allow that to happen.
As a result, Rust can't narrow s's inner 'a lifetime... but if it can't narrow it, then that means 'b must be the full, un-narrowed 'a. But wait, that means that 'b is longer than the lifetime of s itself and i1. And that's impossible.
Hence the failure.
The solution requires two things. First, you need to not over-specify lifetimes. Secondly, you need to ensure that some valid lifetime exists at all; in the case of your original code, that means moving i2 above z0 and z1 so that it outlives them. Like so:
fn f0<'a>(t0: &mut MyItr<'a>, t1: &mut MyItr<'a>, i: &'a i32) {
let t: &mut MyItr<'a> = std::cmp::max(t0, t1);
t.cur = i;
}
fn f1() {
let i0 = 1;
let i1 = 2;
let i2 = 3;
let mut z0 = MyItr { cur: &i0 };
let mut z1 = MyItr { cur: &i1 };
f0(&mut z0, &mut z1, &i2);
}
A rule of thumb: don't just spam a single lifetime everywhere. Only use the same lifetime for things that should be the same.

Related

Lifetime does not live long enough

There is a code that produces the following error:
fn foo<'a, F1, F2>(f: F1)
where
F1: FnOnce(&'a mut i32) -> F2,
F2: FnOnce() + 'a,
{
let mut a = 0;
f(&mut a)();
}
fn main() {
foo(|a| {
|| {
*a += 1;
()
}
});
}
error[E0597]: `a` does not live long enough
--> src/main.rs:7:7
|
1 | fn foo<'a, F1, F2>(f: F1)
| -- lifetime `'a` defined here
...
7 | f(&mut a)();
| --^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `a` is borrowed for `'a`
8 | }
| - `a` dropped here while still borrowed
I'm very confused because error message says that a is still borrowed but foo returns nothing!
Your code has two issues:
a Lifetime issue
it tries to return a closure
1. The lifetime issue
You can reduce the example in your question to
fn foo<'a, F1>(f: F1)
where
F1: FnOnce(&'a mut i32),
{
let mut a = 0;
f(&mut a);
}
fn main() {
foo(|a| {
*a += 1;
});
}
and here you can probably see more clearly, that
fn foo<'a, F1>(f: F1)
where
F1: FnOnce(&'a mut i32)
means, that the caller of foo can decide, what 'a
will be.
But in
let mut a = 0;
f(&mut a);
you create a, which has its concrete lifetime (essentially
the body of foo) and try to call f with it. But 'a which
the caller has chosen, doesn't need to have to do anything
with the lifetime of a, it can be wildly larger for example.
Worded differently
fn foo<'a, F1>(f: F1)
where
F1: FnOnce(&'a mut i32)
means: If you call foo you can hand it something function
like f (function pointer, closure, ...), which needs its parameter
to live at least as long as 'a. 'a could be 'static
for example.
So inside foo you can't just create a thing with its concrete
lifetime and hand if to f, as you don't know, what 'a the
caller of foo will choose.
You might now be surprised, that
fn foo<F1>(f: F1)
where
F1: FnOnce(&mut i32),
{
let mut a = 0;
f(&mut a);
}
fn main() {
foo(|a| {
*a += 1;
});
}
compiles just fine, but that is simply, because foo in this example desugars to
fn foo<F1>(f: F1)
where
F1: for<'a> FnOnce(&'a mut i32),
{
let mut a = 0;
f(&mut a);
}
which means, that not the caller of foo decides, what the lifetime 'a will be, but f has to be something, that can work with a parameter of any lifetime. So foo can choose 'a in this case.
But to be able to return anything, which has the lifetime 'a chosen by foo, you would need to be able to write it into foos signature, which you can't, to the best of my knowledge.
2. it tries to return a closure
The Rust Book, "Returning Closures" tells us, you can't
return closures.
But
fn returns_closure(a: &mut i32) -> impl FnMut() + '_ {
|| {
*a += 1;
println!("{}", *a);
}
}
fn main() {
let mut sum: i32 = 5;
let mut f = returns_closure(&mut sum);
f();
f();
let mut sum2: i32 = 10;
let mut g = returns_closure(&mut sum2);
g();
g();
}
just works fine for me on rustc version 1.58.1.
The Rust Book, "Returning Types that Implement Traits" tells us that you can use the
impl SomeTrait syntax only in return types of functions and methods, which
always return the same concrete type on all function exits.
So the above syntax doesn't apply to closures.
But with generic types we can still do something similar.
fn foo<F1, F2>(f: &mut F1)
where
F1: FnMut(i32) -> F2,
F2: FnMut(),
{
let mut g = f(1);
g();
g();
let mut h = f(2);
h();
h();
}
fn main() {
foo(&mut (|_a: i32| || println!("wtf")));
foo(&mut (|_a: i32| {
let mut a = 5;
move || {
a += 1;
println!("wtf: {}", a);
}
}));
}
still works fine for me. So it seems as long as the compiler can
figure out the concrete types and the closure returning a closures
also always returns the same concrete type, it works for
rustc 1.58.1.
So my guess is, the syntax simply lacks. There needs to be
some syntax to write something like the following pseudo code:
fn foo<F1, F2>(f: &mut F1)
where
F2: FnMut(),
F1: for<'a> FnMut(&'a mut i32) -> F2 + 'a,
{
...
}
I guess the lifetime bound is part of the type at the moment and so
the caller, which chooses F2 would need to know the required lifetime,
that gets choosen in the call ... but thats just guessing.
As the required lifetime bound shouldn't influence the size
needed for the closure returned by f,
something like that might be possible?
In
fn foo2<F1>(f: &mut F1)
where
F1: for<'a> FnMut(&'a mut i32) -> Box<dyn FnMut() + 'a>,
{
...
}
we can neatly express what we want at the unfortunate cost of allocating ...
But now f can of course return different closures with different types
wrapped up in the Box, so it is also more flexible.

Borrow a struct field mutably and pass it to mutable methods

Because rust doesn't track individual field borrows across method calls - it assumes you've borrowed from the whole struct, it's not possible to borrow a field from the struct, return it, and then pass that into other mutable methods. That sounds contrived but I have this exact issue right now.
struct Foo {
x: i32,
y: i32
}
impl Foo {
pub fn borrow_x(&mut self) -> &mut i32 {
&mut self.x
}
pub fn cross_product(&mut self, other: &mut i32) {
self.y *= *other;
*other *= self.y;
}
}
fn main() {
let mut foo = Foo{x: 2, y: 4};
let x_ref = foo.borrow_x();
foo.cross_product(x_ref);
println!("x={} y={}", foo.x, foo.y);
}
This of course isn't permitted in rust, the error from the compiler is:
error[E0499]: cannot borrow `foo` as mutable more than once at a time
--> src/main.rs:20:5
|
19 | let x_ref = foo.borrow_x();
| --- first mutable borrow occurs here
20 | foo.cross_product(x_ref);
| ^^^ ----- first borrow later used here
| |
| second mutable borrow occurs here
My first reaction is to use unsafe to tell the compiler that it doesn't really borrow from self:
pub fn borrow_x<'a>(&mut self) -> &'a mut i32 {
unsafe {
std::mem::transmute::<&mut i32, &'a mut i32>(&mut self.x)
}
}
It works, but it requires that you don't actually break rust's aliasing rules and reference foo.x elsewhere by accident.
Then I thought maybe I could split the struct so that the borrow and cross_product methods are on different sibling structs. This does work:
struct Bar {
x: X,
y: Y,
}
struct X {
inner: i32
}
impl X {
pub fn borrow_x(&mut self) -> &mut i32 {
&mut self.inner
}
}
struct Y {
inner: i32
}
impl Y {
pub fn cross_product(&mut self, other: &mut i32) {
self.inner *= *other;
*other *= self.inner;
}
}
fn main() {
let mut bar = Bar{x: X{inner: 2}, y: Y{inner: 4}};
let x_ref = bar.x.borrow_x();
bar.y.cross_product(x_ref);
println!("x={} y={}", bar.x.inner, bar.y.inner);
}
I think one could ditch the method all-together and pass references to both fields into cross_product as a free function. That should be equivalent to the last solution. I find that kind of ugly though, especially as the number of fields needed from the struct grow.
Are there other solutions to this problem?
The thing to keep in mind is that rust is working at a per-function level.
pub fn cross_product(&mut self, other: &mut i32) {
self.y *= *other;
*other *= self.y;
}
The mutability rules ensure that self.y and other are not the same thing.
If you're not careful you can run into this kind of bug in C++/C/Java quite easily.
i.e. imagine if instead of
let x_ref = foo.borrow_x();
foo.cross_product(x_ref);
you were doing
let y_ref = foo.borrow_y();
foo.cross_product(y_ref);
What value should foo.y end up with? (Allowing these to refer to the same object can cause certain performance optimisations to not be applicable too)
As you mentioned, you could go with a free function
fn cross_product(a: &mut i32, b: &mut i32) {
a *= b;
b *= a;
}
but I'd consider ditching mutability altogether
fn cross_product(a:i32, b:i32) -> (i32,i32) {
(a*b, a*b*b)
}
ASIDE: If the return value seems odd to you (it did to me initially too) and you expected (a*b, a*b) you need to think a little harder... and I'd say that alone is a good reason to avoid the mutable version.
Then I can use it like this
let (_x,_y) = cross_product(foo.x, foo.y);
foo.x = _x;
foo.y = _y;
This is a bit verbose, but when RFC-2909 lands we can instead write:
(foo.y, foo.x) = cross_product(foo.x, foo.y);

Why Rust can't coerce mutable reference to immutable reference in a type constructor?

It is possible to coerce &mut T into &T but it doesn't work if the type mismatch happens within a type constructor.
playground
use ndarray::*; // 0.13.0
fn print(a: &ArrayView1<i32>) {
println!("{:?}", a);
}
pub fn test() {
let mut x = array![1i32, 2, 3];
print(&x.view_mut());
}
For the above code I get following error:
|
9 | print(&x.view_mut());
| ^^^^^^^^^^^^^ types differ in mutability
|
= note: expected reference `&ndarray::ArrayBase<ndarray::ViewRepr<&i32>, ndarray::dimension::dim::Dim<[usize; 1]>>`
found reference `&ndarray::ArrayBase<ndarray::ViewRepr<&mut i32>, ndarray::dimension::dim::Dim<[usize; 1]>>`
It is safe to coerce &mut i32 to &i32 so why it is not applied in this situation? Could you provide some examples on how could it possibly backfire?
In general, it's not safe to coerce Type<&mut T> into Type<&T>.
For example, consider this wrapper type, which is implemented without any unsafe code and is therefore sound:
#[derive(Copy, Clone)]
struct Wrapper<T>(T);
impl<T: Deref> Deref for Wrapper<T> {
type Target = T::Target;
fn deref(&self) -> &T::Target { &self.0 }
}
impl<T: DerefMut> DerefMut for Wrapper<T> {
fn deref_mut(&mut self) -> &mut T::Target { &mut self.0 }
}
This type has the property that &Wrapper<&T> automatically dereferences to &T, and &mut Wrapper<&mut T> automatically dereferences to &mut T. In addition, Wrapper<T> is copyable if T is.
Assume that there exists a function that can take a &Wrapper<&mut T> and coerce it into a &Wrapper<&T>:
fn downgrade_wrapper_ref<'a, 'b, T: ?Sized>(w: &'a Wrapper<&'b mut T>) -> &'a Wrapper<&'b T> {
unsafe {
// the internals of this function is not important
}
}
By using this function, it is possible to get a mutable and immutable reference to the same value at the same time:
fn main() {
let mut value: i32 = 0;
let mut x: Wrapper<&mut i32> = Wrapper(&mut value);
let x_ref: &Wrapper<&mut i32> = &x;
let y_ref: &Wrapper<&i32> = downgrade_wrapper_ref(x_ref);
let y: Wrapper<&i32> = *y_ref;
let a: &mut i32 = &mut *x;
let b: &i32 = &*y;
// these two lines will print the same addresses
// meaning the references point to the same value!
println!("a = {:p}", a as &mut i32); // "a = 0x7ffe56ca6ba4"
println!("b = {:p}", b as &i32); // "b = 0x7ffe56ca6ba4"
}
Full playground example
This is not allowed in Rust, leads to undefined behavior and means that the function downgrade_wrapper_ref is unsound in this case. There may be other specific cases where you, as the programmer, can guarantee that this won't happen, but it still requires you to implement it specifically for those case, using unsafe code, to ensure that you take the responsibility of making those guarantees.
Consider this check for an empty string that relies on content staying unchanged for the runtime of the is_empty function (for illustration purposes only, don't use this in production code):
struct Container<T> {
content: T
}
impl<T> Container<T> {
fn new(content: T) -> Self
{
Self { content }
}
}
impl<'a> Container<&'a String> {
fn is_empty(&self, s: &str) -> bool
{
let str = format!("{}{}", self.content, s);
&str == s
}
}
fn main() {
let mut foo : String = "foo".to_owned();
let container : Container<&mut String> = Container::new(&mut foo);
std::thread::spawn(|| {
container.content.replace_range(1..2, "");
});
println!("an empty str is actually empty: {}", container.is_empty(""))
}
(Playground)
This code does not compile since &mut String does not coerce into &String. If it did, however, it would be possible that the newly created thread changed the content after the format! call but before the equal comparison in the is_empty function, thereby invalidating the assumption that the container's content was immutable, which is required for the empty check.
It seems type coercions don't apply to array elements when array is the function parameter type.
playground

Is it possible to create a wrapper around an &mut that acts like an &mut

The following code fails to compile because MutRef is not Copy. It can not be made copy because &'a mut i32 is not Copy. Is there any way give MutRef similar semantics to &'a mut i32?
The motivation for this is being able to package up a large set of function parameters into a struct so that they can be passed as a group instead of needing to be passed individually.
struct MutRef<'a> {
v: &'a mut i32
}
fn wrapper_use(s: MutRef) {
}
fn raw_use(s: &mut i32) {
}
fn raw_ref() {
let mut s: i32 = 9;
let q = &mut s;
raw_use(q);
raw_use(q);
}
fn wrapper() {
let mut s: i32 = 9;
let q = MutRef{ v: &mut s };
wrapper_use(q);
wrapper_use(q);
}
No.
The name for this feature is "implicit reborrowing" and it happens when you pass a &mut reference where the compiler expects a &mut reference of a possibly different lifetime. The compiler only implicitly reborrows when the actual type and the expected type are both &mut references. It does not work with generic arguments or structs that contain &mut references. There is no way in current Rust to make a custom type that can be implicitly reborrowed. There is an open issue about this limitation dating from 2015, but so far nobody has proposed any way to lift it.
You can always implement your own method to explicitly reborrow:
impl<'a> MutRef<'a> {
// equivalent to fn reborrow(&mut self) -> MutRef<'_>
fn reborrow<'b>(&'b mut self) -> MutRef<'b> {
MutRef {v: self.v}
}
}
fn wrapper() {
let mut s: i32 = 9;
let mut q = MutRef{ v: &mut s };
wrapper_use(q.reborrow()); // does not move q
wrapper_use(q); // moves q
}
See also
Why is the mutable reference not moved here?
Type inference and borrowing vs ownership transfer

When is it useful to define multiple lifetimes in a struct?

In Rust, when we want a struct to contain references, we typically define their lifetimes as such:
struct Foo<'a> {
x: &'a i32,
y: &'a i32,
}
But it's also possible to define multiple lifetimes for different references in the same struct:
struct Foo<'a, 'b> {
x: &'a i32,
y: &'b i32,
}
When is it ever useful to do this? Can someone provide some example code that doesn't compile when both lifetimes are 'a but does compile when the lifetimes are 'a and 'b (or vice versa)?
After staying up way too late, I was able to come up with an example case where the lifetimes matter. Here is the code:
static ZERO: i32 = 0;
struct Foo<'a, 'b> {
x: &'a i32,
y: &'b i32,
}
fn get_x_or_zero_ref<'a, 'b>(x: &'a i32, y: &'b i32) -> &'a i32 {
if *x > *y {
return x
} else {
return &ZERO
}
}
fn main() {
let x = 1;
let v;
{
let y = 2;
let f = Foo { x: &x, y: &y };
v = get_x_or_zero_ref(&f.x, &f.y);
}
println!("{}", *v);
}
If you were to change the definition of Foo to this:
struct Foo<'a> {
x: &'a i32,
y: &'a i32,
}
Then the code won't compile.
Basically, if you want to use the fields of the struct on any function that requires it's parameters to have different lifetimes, then the fields of the struct must have different lifetimes as well.
I want to re-answer my question here since it's still showing up high in search results and I feel I can explain better. Consider this code:
Rust Playground
struct Foo<'a> {
x: &'a i32,
y: &'a i32,
}
fn main() {
let x = 1;
let v;
{
let y = 2;
let f = Foo { x: &x, y: &y };
v = f.x;
}
println!("{}", *v);
}
And the error:
error[E0597]: `y` does not live long enough
--> src/main.rs:11:33
|
11 | let f = Foo { x: &x, y: &y };
| ^^ borrowed value does not live long enough
12 | v = f.x;
13 | }
| - `y` dropped here while still borrowed
14 | println!("{}", *v);
| -- borrow later used here
What's going on here?
The lifetime of f.x has the requirement of being at least large enough to encompass the scope of x up until the println! statement (since it's initialized with &x and then assigned to v).
The definition of Foo specifies that both f.x and f.y use the same generic lifetime 'a, so the lifetime of f.y must be at least as large as f.x.
But, that can't work, because we assign &y to f.y, and y goes out of scope before the println!. Error!
The solution here is to allow Foo to use separate lifetimes for f.x and f.y, which we do using multiple generic lifetime parameters:
Rust Playground
struct Foo<'a, 'b> {
x: &'a i32,
y: &'b i32,
}
Now the lifetimes of f.x and f.y aren't tied together. The compiler will still use a lifetime that's valid until the println! statement for f.x. But there's no longer a requirement that f.y uses the same lifetime, so the compiler is free to choose a smaller lifetime for f.y, such as one that is valid only for the scope of y.
Here is another simple example where the struct definition has to use two lifetimes in order to operate as expected. It does not split the aggregate into fields of different lifetimes, but nests the struct with another struct.
struct X<'a>(&'a i32);
struct Y<'a, 'b>(&'a X<'b>);
fn main() {
let z = 100;
//taking the inner field out of a temporary
let z1 = ((Y(&X(&z))).0).0;
assert!(*z1 == z);
}
The struct Y has two lifetime parameters, one for its contained field &X, and one for X's contained field &z.
In the operation ((Y(&X(&z))).0).0, X(&z) is created as a temporary and is borrowed. Its lifetime is only in the scope of this operation, expiring at the statement end. But since X(&z)'s lifetime is different from the its contained field &z, the operation is fine to return &z, whose value can be accessed later in the function.
If using single lifetime for Y struct. This operation won't work, because the lifetime of &z is the same as its containing struct X(&z), expiring at the statement end; therefore the returned &z is no longer valid to be accessed afterwards.
See code in the playground.

Resources