I recently had an error which was simply resolved by changing
impl<'a> Foo<'a> {
fn foo(&'a self, path: &str) -> Boo<'a> { /* */ }
}
to
impl<'a> Foo<'a> {
fn foo(&self, path: &str) -> Boo { /* */ }
}
which did not make sense according to my understanding, as I thought that the second version is exactly the same as the first with applied lifetime elision.
In case we introduce a new lifetime for the method this seems to be the case according this example from the nomicon.
fn get_mut(&mut self) -> &mut T; // elided
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
So what are the differences between this and my first code snipped.
1. countable noun. The difference between two things is the way in which they are unlike each other. That is the fundamental difference between the two societies. [ + between]
The most common use for among is when something is in or with a group of a few, several, or many things. The most common use of between is when something is in the middle of two things or two groups of things. It is sometimes used in the phrase in between.
This and these are used to point to something near you. For a singular thing, use this. For a plural thing, use these.
Lifetime 'a
in fn foo(&'a self, ...) ...
is defined for impl<'a>
, that is it is the same for all foo
calls.
Lifetime 'a
in fn get_mut<'a>(&'a mut self) ...
is defined for the function. Different calls of get_mut
can have different values for 'a
.
Your code
impl<'a> Foo<'a> { fn foo(&'a self, path: &str) -> Boo<'a> { /* */ } }
is not the expansion of elided lifetime. This code ties lifetime of borrow &'a self
to the lifetime of structure Foo<'a>
. If Foo<'a>
is invariant over 'a
, then self
should remain borrowed as long as 'a
.
Correct expansion of elided lifetime is
impl<'a> Foo<'a> {
fn foo<'b>(&'b self, path: &str) -> Boo<'b> { /* */ }
}
This code doesn't depend on variance of structure Foo
to be able to borrow self
for shorter lifetimes.
Example of differences between variant and invariant structures.
use std::cell::Cell;
struct Variant<'a>(&'a u32);
struct Invariant<'a>(Cell<&'a u32>);
impl<'a> Variant<'a> {
fn foo(&'a self) -> &'a u32 {
self.0
}
}
impl<'a> Invariant<'a> {
fn foo(&'a self) -> &'a u32 {
self.0.get()
}
}
fn main() {
let val = 0;
let mut variant = Variant(&val);// variant: Variant<'long>
let mut invariant = Invariant(Cell::new(&val));// invariant: Invariant<'long>
{
let r = variant.foo();
// Pseudocode to explain what happens here
// let r: &'short u32 = Variant::<'short>::foo(&'short variant);
// Borrow of `variant` ends here, as it was borrowed for `'short` lifetime
// Compiler can do this conversion, because `Variant<'long>` is
// subtype of Variant<'short> and `&T` is variant over `T`
// thus `variant` of type `Variant<'long>` can be passed into the function
// Variant::<'short>::foo(&'short Variant<'short>)
}
// variant is not borrowed here
variant = Variant(&val);
{
let r = invariant.foo();
// compiler can't shorten lifetime of `Invariant`
// thus `invariant` is borrowed for `'long` lifetime
}
// Error. invariant is still borrowed here
//invariant = Invariant(Cell::new(&val));
}
Playground link
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With