Rust lifetime error - rust

Can anyone tell what the lifetime error is in the following code? (simplified from my actual code) I've looked it over myself, but I can't figure out what is wrong or how to fix it. The problem comes when I try to add the Cell, but I'm not sure why.
use std::cell::Cell;
struct Bar<'a> {
bar: &'a str,
}
impl<'a> Bar<'a> {
fn new(foo: &'a Foo<'a>) -> Bar<'a> { Bar{bar: foo.raw} }
}
pub struct Foo<'a> {
raw: &'a str,
cell: Cell<&'a str>,
}
impl<'a> Foo<'a> {
fn get_bar(&self) -> Bar { Bar::new(&self) }
}
The compiler error is
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/foo.rs:15:32
|
15 | fn get_bar(&self) -> Bar { Bar::new(&self) }
| ^^^^^^^^

First, the solution:
use std::cell::Cell;
struct Bar<'a> {
bar: &'a str,
}
impl<'a> Bar<'a> {
fn new(foo: &Foo<'a>) -> Bar<'a> { Bar{bar: foo.raw} }
}
pub struct Foo<'a> {
raw: &'a str,
cell: Cell<&'a str>,
}
impl<'a> Foo<'a> {
fn get_bar(&self) -> Bar<'a> { Bar::new(&self) }
}
There are two problems in your code. The first is with get_bar, where you didn't specify the lifetime for the return type. When you don't specify lifetimes in signatures, Rust doesn't infer the correct lifetimes, it just blindly fills them in based on simple rules. In this specific case, what you get is effectively fn get_bar<'b>(&'b self) -> Bar<'b> which is obviously wrong, given the lifetime of self.raw (which was what you actually wanted) is 'a. See the Rust Book chapter on Lifetime Elision.
The second problem is that you're over-constraining the argument to Bar::new. &'a Foo<'a> means you require a borrow to a Foo for as long as the strings it's borrowing exist. But borrows within a type have to outlive values of said type, so the only lifetime valid in this case is where 'a matches the entire lifetime of the thing being borrowed... and that conflicts with the signature of get_bar (where you're saying &self won't necessarily live as long as 'a since it has its own lifetime). Long story short: remove the unnecessary 'a from the Foo borrow, leaving just &Foo<'a>.
To rephrase the above: the problem with get_bar was that you hadn't written enough constraints, the problem with Bar::new was that you'd written too many.

DK explained which constraints were missing and why, but I figured I should explain why the code was working before I added Cell. It turns out to be due to variance inference.
If you add in the inferred lifetimes to the original code and rename the lifetime variables to be unique, you get
struct Bar<'b> {
bar: &'b str,
}
impl<'b> Bar<'b> {
fn new(foo: &'b Foo<'b>) -> Bar<'b> { Bar{bar: foo.raw} }
}
pub struct Foo<'a> {
raw: &'a str,
cell: Cell<&'a str>,
}
impl<'a> Foo<'a> {
fn get_bar<'c>(&'c self) -> Bar<'c> { Bar::new(&self) }
}
The problem comes when calling Bar::new, because you are passing &'c Foo<'a>, to something expecting &'b Foo<'b>. Normally, immutable types in Rust are covariant, meaning that &Foo<'a> is implicitly convertable to &Foo<'b> whenever 'b is a shorter lifetime than 'a. Without the Cell, &'c Foo<'a> converts to &'c Foo<'c>, and is passed to Bar::new wiht 'b = 'c, so there is no problem.
However, Cell adds interior mutability to Foo, which means that it is no longer safe to be covariant. This is because Bar could potentially try to assign a shorter lived 'b reference back into the original Foo, but Foo requires that all of the references it holds are valid for the longer lifetime 'a. Therefore, interior mutability makes &Foo invariant, meaning you can no longer shorten the lifetime parameter implicitly.

Related

Rust lifetimes for implementing a trait on nested slices

I want to create a wrapper around (nested) slices for easy operations on multidimensional data, owned by a different struct.
The most basic version of the mutable version of my slice wrapper might look like this:
struct MySliceMut<'a> {
data: Vec<&'a mut [f32]>,
}
impl<'a, 'b> MySliceMut<'a> {
fn get(&'b mut self) -> &'a mut [&'b mut [f32]] {
self.data.as_mut_slice()
}
}
Now if I want to implement a trait, for instance AddAssign, Rust does not seem to infer the lifetime of &mut self from the implementing type. The compiler complains that &mut self might outlive 'a:
impl<'a> AddAssign<MySlice<'a>> for MySliceMut<'a> { // lifetime 'a
fn add_assign(&mut self, rhs: MySlice<'a>) { // lifetime '1
let a = self.get(); // lifetime may not live long enough, '1 must outlive 'a
let b = rhs.get();
// do inplace addition here
}
}
Full Code - Rust Playground
I tried to figure out the issue with the lifetimes, but can't find it. Would the trait impl require any additional annotations?
struct MySlice<'a> {
data: Vec<&'a [f32]>,
}
impl<'a, 'b> MySlice<'a> {
fn get(&'b self) -> &'a [&'b [f32]] {
self.data.as_slice()
}
}
Problem with your code is that fn get(&'b self) returns variable with wrong lifetime. Associated lifetime 'a of MySlice<'a> is lifetime of inner slice. Associated lifetime 'b of fn get(...) is lifetime of the self. So I guess the function probably should return &'b [&'a [f32]] instead.
-- Edited --
Make sure to change fn get(...) of MySliceMut either.

Why is explicitly annotating the lifetime required in the first case, but not in the second?

Here, the annotating 'a explicitly for items is required:
struct App<'a> {
items: StatefulList<'a, (&'a str, &'a str, usize)>,
}
impl<'a> App<'a> {
fn new(items: &'a Vec<(&'a str, &'a str, usize)>) -> App<'a> {
App {
items: StatefulList::with_items(items),
}
}
}
However, here it is not:
struct StatefulList<'a, T> {
state: ListState,
items: &'a Vec<T>,
}
impl<'a, T> StatefulList<'a, T> {
fn with_items(items: &Vec<T>) -> StatefulList<T> {
StatefulList {
state: ListState::default(),
items,
}
}
}
Why is that?
For now, I think it is because the compiler can't figure out the lifetime in the first case.
Because of this litte thing:
fn with_items(items: &Vec<T>) -> StatefulList<T> {
// ^ here, where did the lifetime go?
StatefulList is declared with a lifetime. But you omitted the lifetime! What is the lifetime when you omit it?
It is the elided lifetime, '_, or the "figure it out" lifetime. And the compiler "figures it out" via simple liftime elision rules. And part of these rules is that when there is only one lifetime in the parameters (like in this case - the implicit lifetime of the items: &Vec<T>), the lifetimes in the return type all inhreit it. So written explicitly, the signature is:
fn with_items<'b>(items: &'b Vec<T>) -> StatefulList<'b, T>
The 'a lifetime from the impl block is not used at all. The returned StatefulList has the same lifetime as the parameter - which is excellent, because you use the parameter for its items!
In the first case, on the other hand, we explicitly specify the 'a lifetime from the impl block. You still use the parameter, and so the parameter's lifetime has to match - and it has to be 'a too.
There is a lint that will help you avoid that situation: it is called elided_lifetimes_in_paths, and is part of the rust_2018_idioms lints group which I strongly recommend #![forbid]ing for new projects. If you will do that, the compiler will complain:
error: hidden lifetime parameters in types are deprecated
--> src/lib.rs:12:51
|
12 | fn with_items(items: &Vec<T>) -> StatefulList<T> {
| ^ expected named lifetime parameter
|
note: the lint level is defined here
--> src/lib.rs:1:11
|
1 | #![forbid(rust_2018_idioms)]
| ^^^^^^^^^^^^^^^^
= note: `#[forbid(elided_lifetimes_in_paths)]` implied by `#[forbid(rust_2018_idioms)]`
help: consider using the `'_` lifetime
|
12 | fn with_items(items: &Vec<T>) -> StatefulList<'_, T> {
| +++
The thing is that in the second one you do not return anything that has to deal with lifetimes, but an owned version of StatefulList. In the first one it need to match the lifetime to what you are returning, to ensure that the data you return may live enough.
In fact you don't even need some of the annotations, since the compiler will coerce the lifetime for you.
impl<'a> App<'a> {
fn new(items: &'a Vec<(&str, &str, usize)>) -> App<'a> {
App {
items: StatefulList::with_items(items),
}
}
}
&str need to live at least as much as &'a Vec.
Playground

Using different lifetimes in struct implementations

I am trying to get a better understanding of Rust lifetimes.
struct Name<'a> {
arg: &'a u8,
}
impl<'a> Name<'a> {
fn new1(arg: &'a u8) -> Name<'a> {
Name { arg }
}
fn new2<'b>(arg: &'b u8) -> Name<'b> {
Name { arg }
}
}
Is there any difference between functions new1 and new2? I am assuming it would matter if arg was &self? Is there any case where new2 implementation preferred or the other way?
These two methods end up being exactly the same, but it's worth learning why. Along the way, we'll learn about lifetime coercion
One lifetime can be coerced into another lifetime if that second lifetime is shorter than (or rather, is contained by) the first. This is usually notated 'a: 'b, to mean that the lifetime 'a entirely encloses the lifetime 'b. The usual terminology is that 'a outlives 'b. The reasoning for this coercion is that you can always make a lifetime shorter if you need to. If a reference is valid during some lifetime, then it's also valid during any shorter lifetime contained in the longer lifetime.
So with that in mind, what sort of arguments can new1 and new2 take? We have a fixed lifetime 'a since the whole implementation is generic in that lifetime. However, new1 can not only take &'a u8, but any &'b u8 if 'b can be coerced to 'a. That is, 'b: 'a and 'b is longer than 'a.
new2 is slightly different, but it ends up having the same effect. The method is generic in the lifetime 'b and can take any &'c u8 if 'c: 'b. new2 is still technically generic in 'a, but since it doesn't use 'a at all, it can be ignored. That said, ignoring a generic parameter is confusing (why have the parameter at all?), so it would probably be best to use new1 instead.
Another reason to prefer new1 over new2 is that it fits better with Self. If we try to change the outputs to Self
impl<'a> Name<'a> {
fn new1(arg: &'a u8) -> Self {
Name { arg }
}
fn new2<'b>(arg: &'b u8) -> Self {
Name { arg }
}
}
the compiler complains. Why? Now the outputs have to be Name<'a> and in new2, we're returning Name<'b>. This isn't coercible to Name<'a> unless 'b: 'a, so we have to add that as a bound on 'b:
impl<'a> Name<'a> {
fn new1(arg: &'a u8) -> Self {
Name { arg }
}
fn new2<'b: 'a>(arg: &'b u8) -> Self {
Name { arg }
}
}
(playground link)
In this case, it's pretty clear that new1 is superior since it doesn't even need that second lifetime, but still allows exactly the same inputs.

Return reference with lifetime of self

I'd like to write some code like the following:
struct Foo {
foo: usize
}
impl Foo {
pub fn get_foo<'a>(&'a self) -> &'self usize {
&self.foo
}
}
But this doesn't work, failing with invalid lifetime name: 'self is no longer a special lifetime.
How can I return a reference that lives as long as the object itself?
You don't want the reference to live exactly as long as the object. You just want a borrow on the object (quite possibly shorter than the entire lifetime of the object), and you want the resulting reference to have the lifetime of that borrow. That's written like this:
pub fn get_foo<'a>(&'a self) -> &'a usize {
&self.foo
}
Additionally, lifetime elision makes the signature prettier:
pub fn get_foo(&self) -> &usize {
&self.foo
}
In your example the lifetime of self is 'a so the lifetime of the returned reference should be 'a:
pub fn get_foo<'a>(&'a self) -> &'a usize {
&self.foo
}
However the compiler is able to deduce (lifetime elision) the correct lifetime in simple cases like that, so you can avoid to specify lifetime at all, this way:
pub fn get_foo(&self) -> &usize {
&self.foo
}
Look here for lifetime elision rules

Tying a trait lifetime variable to &self lifetime

I'd like to do something along the following lines:
trait GetRef<'a> {
fn get_ref(&self) -> &'a [u8];
}
struct Foo<'a> {
buf: &'a [u8]
}
impl <'a> GetRef<'a> for Foo<'a> {
fn get_ref(&self) -> &'a [u8] {
&self.buf[1..]
}
}
struct Bar {
buf: Vec<u8>
}
// this is the part I'm struggling with:
impl <'a> GetRef<'a> for Bar {
fn get_ref(&'a self) -> &'a [u8] {
&self.buf[1..]
}
The point of the explicit lifetime variable in the GetRef trait is to allow the return value of get_ref() on a Foo object to outlive the Foo itself, tying the return value's lifetime to that of the lifetime of Foo's buffer.
However, I haven't found a way to implement GetRef for Bar in a way that the compiler accepts. I've tried several variations of the above, but can't seem to find one that works. Is there any there any reason that this fundamentally cannot be done? If not, how can I do this?
Tying a trait lifetime variable to &self lifetime
Not possible.
Is there any there any reason that this fundamentally cannot be done?
Yes. An owning vector is something different than a borrowed slice. Your trait GetRef only makes sense for things that already represent a “loan” and don't own the slice. For an owning type like Bar you can't safely return a borrowed slice that outlives Self. That's what the borrow checker prevents to avoid dangling pointers.
What you tried to do is to link the lifetime parameter to the lifetime of Self. But the lifetime of Self is not a property of its type. It just depends on the scope this value was defined in. And that's why your approach cannot work.
Another way of looking at it is: In a trait you have to be explicit about whether Self is borrowed by a method and its result or not. You defined the GetRef trait to return something that is not linked to Self w.r.t. lifetimes. So, no borrowing. So, it's not implementable for types that own the data. You can't create a borrowed slice referring to a Vec's elements without borrowing the Vec.
If not, how can I do this?
Depends on what exactly you mean by “this”. If you want to write a “common denominator” trait that can be implemented for both borrowed and owning slices, you have to do it like this:
trait GetRef {
fn get_ref(&self) -> &[u8];
}
The meaning of this trait is that get_ref borrows Self and returns a kind of “loan” because of the current lifetime elision rules. It's equivalent to the more explicit form
trait GetRef {
fn get_ref<'s>(&self) -> &'s [u8];
}
It can be implemented for both types now:
impl<'a> GetRef for Foo<'a> {
fn get_ref(&self) -> &[u8] { &self.buf[1..] }
}
impl GetRef for Bar {
fn get_ref(&self) -> &[u8] { &self.buf[1..] }
}
You could make different lifetimes for &self and result in your trait like that:
trait GetRef<'a, 'b> {
fn get_ref(&'b self) -> &'a [u8];
}
struct Foo<'a> {
buf: &'a [u8]
}
impl <'a, 'b> GetRef<'a, 'b> for Foo<'a> {
fn get_ref(&'b self) -> &'a [u8] {
&self.buf[1..]
}
}
struct Bar {
buf: Vec<u8>
}
// Bar, however, cannot contain anything that outlives itself
impl<'a> GetRef<'a, 'a> for Bar {
fn get_ref(&'a self) -> &'a [u8] {
&self.buf[1..]
}
}
fn main() {
let a = vec!(1 as u8, 2, 3);
let b = a.clone();
let tmp;
{
let x = Foo{buf: &a};
tmp = x.get_ref();
}
{
let y = Bar{buf: b};
// Bar's buf cannot outlive Bar
// tmp = y.get_ref();
}
}

Resources