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

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

Related

Damned if you do, damned if you don't: Rust compiler complains regardless whether there's a lifetime parameter or not

I am trying to decide whether I should add a lifetime parameter to my impls, but it seems I'm in a "damned if you do, damned if you don't" situation because the compiler complains regardless whether there's a lifetime parameter or not.
pub struct TurtleRef<'a> {
t: &'a BorrowedTurtle<'a>,
}
impl TurtleRef<'_> {
pub fn borrowed_turtle(&self) -> BorrowedTurtle {
*self.t
}
pub fn new(r: Turtle) -> TurtleRef {
TurtleRef{t: &BorrowedTurtle{ t:r}}
}
}
pub struct BorrowedTurtle<'a> {
t: Turtle<'a>,
}
impl<'a> std::ops::Deref for BorrowedTurtle<'_> {
type Target = Turtle<'a>;
fn deref(&self) -> &Self::Target {
&self.t
}
}
impl<'a> std::ops::DerefMut for BorrowedTurtle<'_> {
type Target = Turtle<'a>;
fn deref_mut(&mut self) -> &mut Self::Target {
&self.t
}
}
pub struct Turtle<'a> {
children: Vec<Turtle<'a>>,
}
Turtle has more fields, but I removed them for simplicity. You can see the code snippet here. The code throws the error
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> src/campus.rs:54:6
|
54 | impl<'a> std::ops::Deref for BorrowedTurtle<'_> {
| ^^ unconstrained lifetime parameter
No problem, I'll just remove the parameter since it's causing such a fuss. But after removing it, I get a whole bunch of new errors:
error[E0261]: use of undeclared lifetime name `'a`
--> src/campus.rs:55:26
|
55 | type Target = Turtle<'a>;
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'a` here
|
54 | impl<'a> std::ops::Deref for BorrowedTurtle<'_> {
| ^^^^
help: consider introducing lifetime `'a` here
|
55 | type Target<'a> = Turtle<'a>;
| ^^^^
Whatever you say, I'll just go ahead and add that parameter to target. But now I get yet another error:
error[E0658]: generic associated types are unstable
--> src/campus.rs:55:5
|
55 | type Target<'a> = Turtle<'a>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
So no matter what I do, it seems I run into a major error. How do I stop these errors without starting over from scratch? I'd like to keep the impls, structs, and deref functions, so the only thing I should change is their implementation.
On another note, I get the error
error[E0437]: type `Target` is not a member of trait `std::ops::DerefMut`
--> src/campus.rs:64:5
|
64 | type Target = Turtle<'a>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `std::ops::DerefMut`
because Turtle doesn't implement DerefMut, and in fact Turtle should not implement DerefMut. Is there a slight modification of Turtle which results in something that already implements DerefMut?
There are a couple of issues here. Firstly:
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> src/campus.rs:54:6
|
54 | impl<'a> std::ops::Deref for BorrowedTurtle<'_> {
| ^^ unconstrained lifetime parameter
You either use an anonymous lifetime or you don't. Here, you declare the 'a, so use it:
impl<'a> std::ops::Deref for BorrowedTurtle<'a> {
To use an elided lifetime, you don't have to declare it:
impl std::ops::Deref for BorrowedTurtle<'_> {
However, here you have to refer to the lifetime in Target, so you cannot elide it.
Second:
error[E0437]: type `Target` is not a member of trait `std::ops::DerefMut`
--> src/lib.rs:28:5
|
28 | type Target = Turtle<'a>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `std::ops::DerefMut`
DerefMut does not have a Target member because it reuses that from its supertrait, Deref. This is to ensure that items must Deref and DerefMut to the same Target:
impl<'a> std::ops::Deref for BorrowedTurtle<'a> {
type Target = Turtle<'a>;
fn deref(&self) -> &Self::Target {
&self.t
}
}
impl std::ops::DerefMut for BorrowedTurtle<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.t
}
}
Lastly, you will now get errors that 'a is not used:
error[E0392]: parameter `'a` is never used
--> src/lib.rs:15:27
|
15 | pub struct BorrowedTurtle<'a> {
| ^^ unused parameter
|
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
This is because you have a couple of recursive types where the lifetime isn't actually being used:
// 'a isn't actually used for anything
pub struct Turtle<'a> {
children: Vec<Turtle<'a>>,
}
pub struct BorrowedTurtle<'a> {
t: Turtle<'a>,
}
I will assume that for the purpose of this answer you omitted other relevant fields that use the 'a, so that's all!
Since DerefMut inherit from Deref, you don't have to specify Target, pub trait DerefMut: Deref { use the Target define in Deref implementation.
Deref trait is very special, it can't really be use by "normal" user, almost only std can implement it for new type.
This is because it's borrow self and return a reference of "something else" problem is this something else can't be temporary, std use it control over rust ecosystem to be able to do that for example Vec implementation:
impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
fn deref_mut(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
}
}
as you can see slice is a "fat pointer" so it doesn't need more than a reference to be valid, you can almost only implement Deref to return Target for type like slice.
Another example is for PathBuf:
impl ops::Deref for PathBuf {
type Target = Path;
#[inline]
fn deref(&self) -> &Path {
Path::new(&self.inner)
}
}
Here it's even more clear Path::new create a fat pointer. So, Target can't be something else that something that can't be self contained or already exist in your Self.
As the documentation said:
Because of this, Deref should only be implemented for smart pointers to avoid confusion.
I think what you really want is to implement Borrow. All that said... here a working code:
impl<'a> std::ops::Deref for BorrowedTurtle<'a> {
type Target = Turtle<'a>;
fn deref(&self) -> &Self::Target {
&self.t
}
}
impl std::ops::DerefMut for BorrowedTurtle<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.t
}
}
Do as you wish.

What is the implicit lifetime for the 1st argument when the 2nd argument is annotated with 'a?

While reading Chapter 12.4 of the Rust Book, I stumbled upon this function:
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
vec![]
}
I understand why the code doesn't compile without the explicit lifetime annotation for the contents argument and the return value - the lifetime elision rules do not apply for functions with at least two borrowed arguments.
But I'm curious what's the implicit lifetime annotation for the query argument. I could think of two scenarios:
// Scenario 1
pub fn search<'a>(query: &'a str, contents: &'a str) -> Vec<&'a str> {
vec![]
}
// Scenario 2
pub fn search<'a, 'b>(query: &'b str, contents: &'a str) -> Vec<&'a str> {
vec![]
}
Both scenarios compile, so query gets either lifetime 'a or 'b. Which one is correct?
From the rustonomicon, under lifetime elision:
Each elided lifetime in input position becomes a distinct lifetime parameter.
You can try assigning the function to a wrong type. Compiler will tell you the correct type of the function:
let x: () = search;
Playground
Result:
error[E0308]: mismatched types
--> src/main.rs:6:17
|
6 | let x: () = search;
| -- ^^^^^^ expected `()`, found fn item
| |
| expected due to this
|
= note: expected unit type `()`
found fn item `for<'r, 'a> fn(&'r str, &'a str) -> Vec<&'a str> {search}`
So, type of your function is:
for<'r, 'a> fn(&'r str, &'a str) -> Vec<&'a str> {search}
Also, if query also had lifetime 'a, you should be able to do this:
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
vec![query]
}
But this fails to compile because query's lifetime is not 'a.
Playground
One way to think of it is that we're not 'giving' a lifetime with lifetime annotations, but describing how the lifetime of your return value relates to the lifetimes of your inputs.
Lifetimes already exist, but annotations let us set relations between them. As you never relate the lifetime of query to anything else in situation 2, we shouldn't really need to name it. Intuitively this makes sense as the most common case and the one that the compiler should (does) infer if you make no annotation on query.

How to infer an appropriate lifetime for an implementation using lifetimes for structs and impl?

How do I resolve this error? What exactly am I telling the compiler when I use the "anonymous lifetime" in impl?
struct LineHandlerInfo<'a> {
label: &'a str,
match_literal: &'a str,
f: fn(&str) -> Option<&str>,
}
struct Game<'a> {
handlers: Vec<LineHandlerInfo<'a>>,
}
impl Game<'_> {
fn match_str<'a>(
&'a mut self,
label: &'a str,
match_literal: &'a str,
mut f: fn(&str) -> Option<&str>,
) {
let mut lh = LineHandlerInfo {
label,
match_literal,
f,
};
self.handlers.push(lh);
}
}
fn main() {
let mut g = Game {
handlers: Vec::new(),
};
g.match_str("echo hello", "hello", |s| {
println!("{}", s);
None
});
}
When I attempt to compile, I get the following error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:18:22
|
18 | let mut lh = LineHandlerInfo {
| ^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the method body at 12:18...
--> src/main.rs:12:18
|
12 | fn match_str<'a>(
| ^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:19:13
|
19 | label,
| ^^^^^
note: but, the lifetime must be valid for the lifetime '_ as defined on the impl at 11:11...
--> src/main.rs:11:11
|
11 | impl Game<'_> {
| ^^
= note: ...so that the expression is assignable:
expected LineHandlerInfo<'_>
found LineHandlerInfo<'_>
How do I resolve this error and what exactly am I telling the compiler when I specify a lifetime on impl Game when I already have a lifetime on the struct?
How do I resolve this error and what exactly am I telling the compiler when I specify a lifetime on impl Game when I already have a lifetime on the struct?
I suspect your confusion stems from an incomplete understanding of the way in which lifetimes are declared and used in Rust.
Struct Lifetimes
In order to use a lifetime on a struct, you declare the lifetime inside the <> adjacent to the name of the struct you are declaring, and then refer to that lifetime inside the struct definition. Importantly, note that the lifetime declared there is scoped to the struct definition - it has no meaning outside.
For example (using the MRE that #Shepmaster provided):
struct Game<'a> {
handlers: Vec<&'a str>,
}
The struct Game contains a vector of references to strings, and the strings which are referenced must last at least as long as the Game struct.
Impl Lifetimes
When using a lifetime specifier on an impl block, you declare the lifetime inside the <> adjacent to the impl keyword, after which you may refer to the lifetime both in the struct being implemented, and inside the implementation itself, like this:
impl<'b> Game<'b> {
fn match_str(&mut self, label: &'b str) {
self.handlers.push(label);
}
}
Note that I am using an entirely different lifetime name here ('b) to illustrate that the the lifetime declaration on the struct is independent of the one on the impl block.
Breaking this down:
impl<'b>
This means that we are defining an implementation for a struct, and within that definition we will use the lifetime 'b
Game<'b> {
This means that the impl is for the struct Game with lifetime 'b - so any references to self inside this implementation are going to automatically have lifetime 'b as well.
fn match_str(&mut self, label: &'b str) {
Here we define the method match_str which takes an argument label. label is a string slice which also has the lifetime 'b - so it must last at least as long as the self that the method is called on.
In your original code, you had something like this:
impl Game<'_> {
fn match_str<'a>(&mut self, label: &'a str) {
...
}
}
This was telling the compiler:
That you are starting a new impl block that, and there are no lifetimes declared at impl level
That the implementation is for the struct Game; this struct has a lifetime parameter but we don't care about it and we are not going to tie it to any element of the implementation
We are defining a method match_str, and we are declaring a lifetime 'a which we can refer to in the rest of the function signature
We have an argument label which has the lifetime a, but we aren't relating this lifetime to anything else
More information:
Rust Book - Lifetime Annotations in Struct Definitions
Rust Book - Lifetime Annotations in Method Definitions
How do I resolve this error?
Remove the generic lifetime from the function, provide a name for the lifetime on the impl block instead of using the anonymous lifetime, then use the named lifetime in the function arguments. Remove the lifetime from &self:
impl<'a> Game<'a> {
fn match_str(&mut self, label: &'a str, match_literal: &'a str, f: fn(&str) -> Option<&str>) {
self.handlers.push(LineHandlerInfo {
label,
match_literal,
f,
});
}
}
See also:
Cannot borrow as mutable more than once at a time in one code - but can in another very similar
What exactly am I doing when I use the "anonymous lifetime" in impl?
You are effectively stating "I know there's a lifetime here, but I don't care about it". However, that's not true for your case; you do care about the lifetime that parameterizes the type because that's what your variables need to match.
See also:
'_, the anonymous lifetime in the Edition Guide
for a struct with a function pointer in it
This has nothing to do with function pointers. When encountering problems while programing, I recommend creating a minimal, reproducible example, stripping out things that don't make the error go away. This allows you to focus on exactly the problem at hand. For example, this reproduces the same error:
struct Game<'a> {
handlers: Vec<&'a str>,
}
impl Game<'_> {
fn match_str<'a>(&mut self, label: &'a str) {
self.handlers.push(label);
}
}

Chaining a sequence of things that are either owned or referenced

I'm attempting to have a trait for things that can either simply contain other things, or create them on demand, given a thing's name. Those contained things should in turn be able to do the same, creating a hierarchy of sorts. Here's a minimal code:
use std::ops::Deref;
pub enum BoxOrRef<'a, T: ?Sized + 'a> {
Boxed(Box<T>),
Ref(&'a T),
}
impl<'a, T: ?Sized + 'a> Deref for BoxOrRef<'a, T> {
type Target = T;
fn deref(&self) -> &T {
match self {
BoxOrRef::Boxed(b) => &b,
BoxOrRef::Ref(r) => r,
}
}
}
pub trait Elem {
fn get_subelem<'a, 'b>(&'a self, name: &'b str) -> Option<BoxOrRef<'a, dyn Elem>>;
}
pub trait Table {
fn get_elem<'a, 'b>(&'a self, name: &'b str) -> Option<BoxOrRef<'a, dyn Elem>>;
}
fn resolve_name<'a, T: Table + ?Sized>(
table: &'a T,
name: &[String],
) -> Option<BoxOrRef<'a, dyn Elem>> {
let mut segments = name.iter();
if let Some(first_segment) = segments.next() {
segments.fold(table.get_elem(&first_segment), |res, next| {
res.and_then(|elem| elem.get_subelem(next))
})
} else {
None
}
}
The lifetime checker however, is not satisfied by this:
error[E0597]: `elem` does not live long enough
--> src/lib.rs:33:33
|
33 | res.and_then(|elem| elem.get_subelem(next))
| ^^^^ - borrowed value only lives until here
| |
| borrowed value does not live long enough
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 26:17...
--> src/lib.rs:26:17
|
26 | fn resolve_name<'a, T: Table + ?Sized>(
| ^^
I need to somehow extend lifetimes of the intermediate res's. I guess I could put them in a struct and tweak the return type of resolve_name to return it along with the final element, but that strikes me as rather clumsy way of doing it. Is there a better solution?
The return value of get_subelem can't outlive the &self borrow you used to call it, because the signature of get_subelem says so explicitly:
fn get_subelem<'a, 'b>(&'a self, name: &'b str) -> Option<BoxOrRef<'a, dyn Elem>>;
// ^^ ^^
In order to get a BoxOrRef<'a, _>, you have to borrow self for the lifetime 'a. In the caller, elem can't outlive the closure it belongs to, and get_subelem borrows elem, so it can't return a value that can escape that closure either.
You're trying to do something that is unsafe, and the compiler is right to stop you. In theory, table.get_elem could return a Boxed value, and elem.get_subelem could return an internal reference, and then the Box would be dropped when the closure returns, invalidating the reference.
Presumably that doesn't actually happen, so you have to tell the compiler that. One way is to decouple &self from BoxOrRef<'a, _>:
pub trait Elem<'a> {
fn get_subelem(&self, name: &str) -> Option<BoxOrRef<'a, dyn Elem<'a>>>;
}
The above change will make your example compile once you add lifetime parameters to all the Elems, but it puts you in an awkward position when implementing Elem: you can't return a reference to self, so practically everything has to be Boxed.
It's hard to make a good recommendation given the vagueness of the example, but I suggest you take a step back and think about whether BoxOrRef is the right abstraction here. Fundamentally, you can't do anything with a BoxOrRef that you couldn't do with a reference, because the BoxOrRef might be a reference. At the same time, you can't do anything with it that you couldn't do with a Box, because it might be a Box. std::borrow::Cow uses ToOwned to implement Clone and into_owned -- perhaps a similar approach could work for you. (And if you can, maybe just implement ToOwned for dyn Elem and use Cow directly.)

Restrict lifetime parameter to scope of parameters of a function

Consider the following example
trait MyTrait<'a> {
type N: 'a;
fn func(&'a self) -> Self::N;
}
fn myfunc<'a, T: 'a + MyTrait<'a>>(g: T) {
g.func();
}
fn main() {}
Compiling this small program fails with:
error[E0597]: `g` does not live long enough
--> src/main.rs:8:5
|
8 | g.func();
| ^ borrowed value does not live long enough
9 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 7:1...
--> src/main.rs:7:1
|
7 | fn myfunc<'a, T: 'a + MyTrait<'a>>(g: T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As far as I understand, the lifetime parameter 'a is not restricted and could be arbitrary. However, g is a parameter and its lifetime is only the function scope, therefore it does not satisfy the condition of lifetime 'a in the definition of method func.
What I really want is that the associated type N is always restricted to the lifetime of self in MyTrait. That's why I came up with the explicit lifetime parameter 'a of MyTrait. I want function myfunc to work, i.e. 'a should somehow be restricted to the lifetime of of the parameter g.
What is the "correct" way to solve this problem?
A very simple example is
struct MyPtr<'a> {
x: &'a usize,
}
struct MyStruct {
data: Vec<usize>,
}
impl<'a> MyTrait<'a> for MyStruct {
type N = MyPtr<'a>;
fn func(&'a self) -> Self::N {
MyPtr { x: &self.data[0] }
}
}
Note that this is extremely simplified, of course. The idea is that N always contains a reference to something contained in MyTrait and should therefore never outlive MyTrait.
What you want is not to bind a generic lifetime, but to allow "any" lifetime:
fn myfunc<T: for<'a> MyTrait<'a>>(g: T) {
g.func();
}
Fully working example in the playground.
The best source for an explanation is How does for<> syntax differ from a regular lifetime bound?.

Resources