Lifetime does not live long enough - rust

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.

Related

Implement mem::swap in rust without std lib

I am trying to write a mem::swap function without using any std lib functions. i am totally new to rust and still trying to make sense of how to use rust language.
below is my code
fn swap<T: std::fmt::Display>(x: &mut T, y: &mut T) {
unsafe {
// Give ourselves some scratch space to work with
let mut t: &mut T = y;
y = x;
x = t;
}
}
fn main() {
println!("Hello, world!");
let mut x = Box::new(5);
let mut y = Box::new(42);
let mut t = Box::new(0);
swap(&mut x, &mut y);
}
and i am facing below error
error: lifetime may not live long enough
--> src/main.rs:4:29
|
1 | fn swap<T: std::fmt::Display>(x: &mut T, y: &mut T) {
| - - let's call the lifetime of this reference `'2`
| |
| let's call the lifetime of this reference `'1`
...
4 | let mut t: &mut T = y;
| ^ assignment requires that `'2` must outlive `'1`
|
help: consider introducing a named lifetime parameter
|
1 | fn swap<'a, T: std::fmt::Display>(x: &'a mut T, y: &'a mut T) {
| +++ ++ ++
what does 'lifetime may not live long enough' mean ?
is there a simple way to write mem::swap code in rust ?
You need to Copy the data. The reference you're using is useless for this purpose. You need to actually alter what both x and y reference.
For example:
fn swap<T>(a: &mut T, b: &mut T) where T : Copy {
(*a,*b) = (*b, *a)
}
fn main() {
let mut a = 1;
let mut b = 2;
swap(&mut a,&mut b);
println!("a={}, b={}", a, b);
}
If you set up the conditions here, it's really a one-liner, Rust will figure out the "temporary" stuff for you. In fact, having a function to do this is actually kind of overkill, since you can just do that single line anywhere in your code as you would normally.
Maybe you want to optimize this around boxed values, taking Box<T> as an argument instead, in which case you could swap references within the box instead of copying, but that's a specialization.
How about using core::ptr::swap to swap raw pointers *mut T.
use core::ptr::swap;
fn custom_swap<T>(x: &mut T, y: &mut T) {
unsafe {
(x as *mut T).swap(y as *mut T);
}
}
fn main() {
println!("Hello, world!");
let mut x = Box::new(5);
let mut y = Box::new(42);
println!("x={}, y={}", x, y);
custom_swap(&mut x, &mut y);
println!("x={}, y={}", x, y);
}
output
Hello, world!
x=5, y=42
x=42, y=5

capturing in closures in Rust '21

I just found out that the following code compiles in Rust 21 (used to not compile in 18)
fn get_func (i: &mut i32) -> impl Fn() -> i32 + '_ {
|| *i
}
Is there an implicit move of i involved ? If so, then why does the following code compile too?
fn get_func (i: &mut i32) -> impl Fn() -> i32 + '_ {
let f = || *i;
println!("{:?}", i); // was expecting here to give borrow of moved variable error, `&mut` doesnt implement `Copy` trait
f
}
Or instead is it implicitly moving (copying in this case) the value being pointed to? But then the following code should compile, which doesn't -- indicating it's moving the reference.
fn get_func (i: &mut i32) -> impl Fn() -> i32 {
|| *i
}
It's downgrading your &mut to a & and making as many copies as it needs to.
This is all a byproduct of the fact that &mut has all the permissions of &; in other words it's fine to downgrade from a mutable reference to a non-mutable reference, and it's fine to copy a non-mutable reference as many times as you want, so this is just doing both of those implicitly.
fn get_func (i: &mut i32) -> impl Fn() -> i32 + '_ {
*i += 1; // fine, still mutable
let f = || *i;
println!("{}", *i); // fine, no mutability required
*i += 1; // ERROR: cannot mutate *i while borrowed by f
f
}
It's worth noting that if you actually do try to capture it as mutable, this happens.
fn get_func (i: &mut i32) -> impl FnMut() -> i32 + '_ {
println!("{}", *i); // Fine
*i += 1; // Fine
let f = || {*i += 1; *i};
println!("{}", *i); // ERROR: cannot borrow *i as immutable
f
}
Also the lifetime doesn't refer to the return of the closure, but the closure itself. Because no memory is moved, the closure is only valid so long as the memory at i's address remains valid. That's why removing the lifetime makes the code not compile.
In any case, all you really have to remember is the classic: "one mutable reference OR multiple immutable references, not both".

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

Why do `mut` and non-`mut` referrence fields have different lifetimes when returned from a getter? [duplicate]

This code works fine (Playground):
struct F<'a> {
x: &'a i32,
}
impl<'a> F<'a> {
fn get<'b>(&'b self) -> &'a i32 {
self.x
}
}
fn main() {
let x = 3;
let y = F { x: &x };
let z = y.get();
}
But when I change x to be a mutable reference instead (Playground):
struct Foo<'a> {
x: &'a mut i32, // <-- `mut` added
}
impl<'a> Foo<'a> {
fn get(&self) -> &'a i32 {
self.x
}
}
fn main() {
let mut x = 3; // <-- `mut` added
let y = Foo { x: &mut x }; // <-- `mut` added
let z = y.get();
}
I get this error:
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> src/main.rs:7:9
|
7 | self.x
| ^^^^^^
|
note: ...the reference is valid for the lifetime 'a as defined on the impl at 5:6...
--> src/main.rs:5:6
|
5 | impl<'a> Foo<'a> {
| ^^
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 6:5
--> src/main.rs:6:5
|
6 | / fn get(&self) -> &'a i32 {
7 | | self.x
8 | | }
| |_____^
Why does that happen? As far as I see it, nothing about the lifetimes has changed: all values/references still live exactly as long as in the first code snippet.
Why does the Rust compiler reject this implementation of get? Because it allows:
The following is a perfectly reasonable main, assuming that get compiles:
fn main() {
let mut x = 3;
let y = Foo { x: &mut x };
let a = y.get();
let b = y.x;
println!("{} {}", a, b);
}
Yet if get were to compile, this would be fine:
a does not borrow y because the lifetime is different
b "consumes" y (moving from y.x) but we do not reuse it after
So everything is fine, except that we now have a &i32 and &mut i32 both pointing to x.
Note: to make it compile, you can use unsafe inside of get: unsafe { std::mem::transmute(&*self.x) }; scary, eh?
At the heart of the borrow-checking algorithm is the cornerstone on which Rust's memory safety is built:
Aliasing XOR Mutability
Rust achieves memory safety without garbage collection by guaranteeing that whenever you are modifying something, no observer can have a reference inside that something that could become dangling.
This, in turns, lets us interpret:
&T as an aliasing reference; it is Copy
&mut T as a unique reference; it is NOT Copy, as it would violate uniqueness, but it can be moved
This difference saved us here.
Since &mut T cannot be copied, the only way to go from &mut T to &T (or &mut T) is to perform a re-borrowing: dereference and take a reference to the result.
This is done implicitly by the compiler. Doing it manually makes for a somewhat better error message:
fn get<'b>(&'b self) -> &'a i32 {
&*self.x
}
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> <anon>:7:9
|
7 | &*self.x
| ^^^^^^^^
|
help: consider using an explicit lifetime parameter as shown: fn get(&'a self) -> &'a i32
--> <anon>:6:5
|
6 | fn get<'b>(&'b self) -> &'a i32 {
| ^
Why cannot it infer a lifetime? Because lifetime of the re-borrow is limited by 'b but we are requiring a 'a and there's no relationship between the two!
By the way, this is what is saving us from blunder here, because it ensures that the instance Foo must be borrowed while the result lives (preventing us to use a mutable reference via Foo::x).
Following the compiler hint, and returning &'b i32 works... and prevents the above main from compiling:
impl<'a> Foo<'a> {
fn get<'b>(&'b self) -> &'b i32 {
&*self.x
}
}
fn main() {
let mut x = 3;
let y = Foo { x: &mut x };
let a = y.get();
let b = y.x;
println!("{} {}", a, b);
}
error[E0505]: cannot move out of `y.x` because it is borrowed
--> <anon>:16:9
|
15 | let a = y.get();
| - borrow of `y` occurs here
16 | let b = y.x;
| ^ move out of `y.x` occurs here
However it lets the first main compile without issue:
fn main() {
let mut x = 3;
let y = Foo { x: &mut x };
let z = y.get();
println!("{}", z);
}
Prints 3.

How to resolve lifetime error for mutable reference in 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.

Resources