Ensure that one lifetime outlives another in tree - rust

I'm having a hard time figuring out the lifetime syntax that I need for the following code, which does not compile. The basic idea is that I'm creating an Abstract Syntax Tree, and each node must have a different type. Some node types must hold a reference to an external value. It's not possible to make this external value an owned type; it's actually a reference to disk file that must be shared by a number of nodes. Here's the code, as simple as I can make it:
trait Node {
fn init(&mut self, my_str: &str);
}
struct NodeParent {
pub children: Vec<Box<dyn Node>>,
}
impl Node for NodeParent {
fn init(&mut self, my_str: &str) {
for child in self.children.iter_mut() {
child.init(my_str);
}
}
}
struct NodeLeaf<'a> {
pub my_str: Option<&'a str>,
}
impl Node for NodeLeaf<'_> {
fn init(&mut self, my_str: &str) {
self.my_str = Some(my_str);
}
}
impl NodeLeaf<'_> {
pub fn new() -> Box<dyn Node> {
Box::new(NodeLeaf { my_str: None })
}
}
pub fn make_ast() {
let mut parent = NodeParent { children: vec![] };
let leaf = NodeLeaf::new();
parent.children.push(leaf);
let some_string = String::from("foo");
let my_str = some_string.as_str();
parent.init(my_str);
}
The error is:
error: lifetime may not live long enough
--> src/query/lifetime_test.rs:23:9
|
22 | fn init(&mut self, my_str: &str) {
| --------- - let's call the lifetime of this reference `'1`
| |
| has type `&mut NodeLeaf<'2>`
23 | self.my_str = Some(my_str);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
I know I need some kind of lifetime on &my_str everywhere it appears, but once I start taking the compiler's suggestion to start adding lifetimes here and there they proliferate, and I never get to code that compiles. I've also tried to Rc<>, but the code to make that work eludes me as well.
How do I specify that &my_str outlives the whole Node tree?
Link to the code on Rust Playground

Add a lifetime to Node:
trait Node<'a> {
fn init(&mut self, my_str: &'a str);
}
struct NodeParent<'a> {
pub children: Vec<Box<dyn Node<'a>>>,
}
impl<'a> Node<'a> for NodeParent<'a> {
fn init(&mut self, my_str: &'a str) {
for child in self.children.iter_mut() {
child.init(my_str);
}
}
}
struct NodeLeaf<'a> {
pub my_str: Option<&'a str>,
}
impl<'a> Node<'a> for NodeLeaf<'a> {
fn init(&mut self, my_str: &'a str) {
self.my_str = Some(my_str);
}
}
impl<'a> NodeLeaf<'a> {
pub fn new() -> Box<dyn Node<'a>> {
Box::new(NodeLeaf { my_str: None })
}
}
But this is not enough, because Box<dyn Node<'a>> is actually Box<dyn Node<'a> + 'static>, that is, it cannot contain any non-'static lifetime. You need to specify that it can contain lifetime 'a:
struct NodeParent<'a> {
pub children: Vec<Box<dyn Node<'a> + 'a>>,
}
impl<'a> NodeLeaf<'a> {
pub fn new() -> Box<dyn Node<'a> + 'a> {
Box::new(NodeLeaf { my_str: None })
}
}
Now you will get a different error:
error[E0597]: `some_string` does not live long enough
--> src/lib.rs:39:18
|
39 | let my_str = some_string.as_str();
| ^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
40 | parent.init(my_str);
41 | }
| -
| |
| `some_string` dropped here while still borrowed
| borrow might be used here, when `parent` is dropped and runs the destructor for type `NodeParent<'_>`
|
= note: values in a scope are dropped in the opposite order they are defined
Because Box<dyn Node> may have an arbitrary destructor, and it may access the stored string, we need to make sure it is still alive when the value is dropped. Do that by moving the string creation before the nodes:
pub fn make_ast() {
let some_string = String::from("foo");
let mut parent = NodeParent { children: vec![] };
let leaf = NodeLeaf::new();
parent.children.push(leaf);
let my_str = some_string.as_str();
parent.init(my_str);
}
Playground.

Related

Borrowed value does not live long enough requiring static lifetime

I'm getting this error with a sample code at this rust playground
Compiling playground v0.0.1 (/playground)
error[E0597]: `text` does not live long enough
--> src/main.rs:34:38
|
34 | let item = NotLongEnough { text: &text };
| ^^^^^ borrowed value does not live long enough
35 | let mut wrapper = Container { buf: Vec::new() };
36 | wrapper.add(Box::new(item));
| -------------- cast requires that `text` is borrowed for `'static`
...
40 | }
| - `text` dropped here while still borrowed
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground`
To learn more, run the command again with --verbose.
The contents are:
trait TestTrait {
fn get_text(&self) -> &str;
}
#[derive(Copy, Clone)]
struct NotLongEnough<'a> {
text: &'a str,
}
impl<'a> TestTrait for NotLongEnough<'a> {
fn get_text(&self) -> &str {
self.text
}
}
struct Container {
buf: Vec<Box<dyn TestTrait>>,
}
impl Container {
pub fn add(&mut self, item: Box<dyn TestTrait>) {
self.buf.push(item);
}
pub fn output(&self) {
for item in &self.buf {
println!("{}", item.get_text());
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let text = "test".to_owned();
let item = NotLongEnough { text: &text };
let mut wrapper = Container { buf: Vec::new() };
wrapper.add(Box::new(item));
wrapper.output();
Ok(())
}
I have no clue why cast requires that text is borrowed for 'static
Could someone please help me with this? I've no idea what I've done wrong.
TLDR: Fixed version
The problem is in your Container definition:
struct Container {
buf: Vec<Box<dyn TestTrait>>,
}
The statement dyn TestTrait is equivalent to dyn TestTrait + 'static, meaning that your trait objects must not contain any references with lifetime less than 'static.
In order to fix the problem, you have to replace that trait bound with a less strict one:
struct Container<'a> {
buf: Vec<Box<dyn TestTrait + 'a>>,
}
Now instead of 'static, the container requires 'a. And you have to apply that change to the implementation as well:
pub fn add(&mut self, item: Box<dyn TestTrait + 'a>) { // notice the new trait-bound
self.buf.push(item);
}
Relevant resources:
Trait bounds

Lifetime error when creating mutable iterator

I had some problems when I tried to create a custom iterator. The non-mutable version worked fine but when copying the same function to create a mutable version, a lifetime error appeared. This is a simplified version of my problem:
struct Test {
map: HashMap<u32, String>
}
impl Test {
pub fn iter(&self, start: u32, end: u32) -> impl Iterator<Item = &String> {
(start..=end).filter_map(move |i| {
self.map.get(&i)
})
}
pub fn iter_mut(&mut self, start: u32, end: u32) -> impl Iterator<Item = &mut String> {
(start..=end).filter_map(move |i| {
self.map.get_mut(&i)
})
}
}
The iter function works fine but the iter_mut function doesn't compile with this error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:21:22
|
21 | self.map.get_mut(&i)
| ^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 20:34...
--> src/main.rs:20:34
|
20 | (start..=end).filter_map(|i| {
| ^^^
note: ...so that closure can access `self`
--> src/main.rs:21:13
|
21 | self.map.get_mut(&i)
| ^^^^^^^^
note: but, the lifetime must be valid for the anonymous lifetime defined on the method body at 19:21...
--> src/main.rs:19:21
|
19 | pub fn iter_mut(&mut self, start: u32, end: u32) -> impl Iterator<Item = &mut String> {
| ^^^^^^^^^
note: ...so that the types are compatible
--> src/main.rs:19:57
|
19 | pub fn iter_mut(&mut self, start: u32, end: u32) -> impl Iterator<Item = &mut String> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `std::option::Option<&mut std::string::String>`
found `std::option::Option<&mut std::string::String>`
As said Todd, compile error on iter_mut likely occurs due to creation many mutable references to the same HashMap, but I'm not sure about that. You can do something like that:
struct Test {
map: HashMap<u32, String>
}
impl Test {
pub fn iter(&self, start: u32, end: u32) -> impl Iterator<Item=&String> {
self.map
.iter()
.filter_map(move |k| {
if (start..=end).contains(k.0) {
Some(k.1)
} else {
None
}
})
}
pub fn iter_mut(&mut self, start: u32, end: u32) -> impl Iterator<Item=&mut String> {
self.map
.iter_mut()
.filter_map(move |k| {
if (start..=end).contains(k.0) {
Some(k.1)
} else {
None
}
})
}
}

How can I fix "cannot infer an appropriate lifetime for autoref" when implementing an iterator that returns mutable references?

I'm trying to write a mutable iterator for a linked list called Thread where each element implements Block.
trait Block<'a> {
fn next(&mut self) -> Option<&'a mut (dyn Block<'a> + 'a)> {
None
}
}
pub struct Thread<'a> {
head: Box<dyn Block<'a> + 'a>,
}
impl<'a> Thread<'a> {
fn iter_mut(&mut self) -> ThreadIterator<'a> {
ThreadIterator {
next: Some(self.head.as_mut()),
}
}
}
pub struct ThreadIterator<'a> {
next: Option<&'a mut (dyn Block<'a> + 'a)>,
}
impl<'a> Iterator for ThreadIterator<'a> {
type Item = &'a mut (dyn Block<'a> + 'a);
fn next(&mut self) -> Option<&'a mut (dyn Block<'a> + 'a)> {
self.next.take().map(|mut block| {
self.next = block.next();
block
})
}
}
Compiling this will output the error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:14:34
|
14 | next: Some(self.head.as_mut()),
| ^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 12:5...
--> src/lib.rs:12:5
|
12 | / fn iter_mut(&mut self) -> ThreadIterator<'a> {
13 | | ThreadIterator {
14 | | next: Some(self.head.as_mut()),
15 | | }
16 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:14:24
|
14 | next: Some(self.head.as_mut()),
| ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 11:6...
--> src/lib.rs:11:6
|
11 | impl<'a> Thread<'a> {
| ^^
note: ...so that the types are compatible
--> src/lib.rs:14:24
|
14 | next: Some(self.head.as_mut()),
| ^^^^^^^^^^^^^^^^^^
= note: expected `dyn Block<'_>`
found `dyn Block<'a>`
This is why I need the 'a requirement for all Blocks (they are borrowing a Runtime):
struct Runtime {}
struct ExampleBlock<'a> {
runtime: &'a Runtime,
next: Box<dyn Block<'a> + 'a>,
}
impl<'a> Block<'a> for ExampleBlock<'a> {
fn next(&mut self) -> Option<&'a mut (dyn Block<'a> + 'a)> {
Some(self.next.as_mut())
}
}
The first thing I tried was removing the mutable requirement from all references. Same errors.
I think the error is telling me that self.head.as_mut() is outliving self.head, so I must ensure that the lifetime of that reference is shorter than Thread<'a>. I thought I fulfilled this requirement with the 'a lifetime for ThreadIterator<'a>. In other words, you can't possibly drop Thread before ThreadIterator, right?
Edit:
I changed Block to a struct to simplify the code, though I need it to be a trait in the end.
struct Block {}
impl<'a> Block {
fn next(&mut self) -> Option<&'a mut Block> {
None
}
}
pub struct Thread {
head: Block,
}
impl<'a> Thread {
fn iter_mut(&mut self) -> ThreadIterator<'a> {
ThreadIterator {
next: Some(&mut self.head),
}
}
}
pub struct ThreadIterator<'a> {
next: Option<&'a mut Block>,
}
impl<'a> Iterator for ThreadIterator<'a> {
type Item = &'a mut Block;
fn next(&mut self) -> Option<&'a mut Block> {
self.next.take().map(|mut block| {
self.next = block.next();
block
})
}
}
It is based off of https://rust-unofficial.github.io/too-many-lists/second-iter-mut.html.
The answer to `cannot infer an appropriate lifetime for autoref due to conflicting requirements` but can't change anything due to trait definition constraints was to introduce a Option for the iterator, which I have done. Lifetime parameter problem in custom iterator over mutable references and Reimplementation of LinkedList: IterMut not compiling didn't answer my question, though I have a hard time connecting my code to theirs.
I finally found something that does work:
pub struct Block {}
impl<'a> Block {
fn next(&mut self) -> Option<&'a mut Block> {
None
}
}
pub struct Thread {
head: Block,
}
impl Thread {
fn iter_mut(&mut self) -> ThreadIterator<'_> { // The lifetime here is changed
ThreadIterator {
next: Some(&mut self.head),
}
}
}
pub struct ThreadIterator<'a> {
next: Option<&'a mut Block>,
}
impl<'a> Iterator for ThreadIterator<'a> {
type Item = &'a mut Block;
fn next(&mut self) -> Option<&'a mut Block> {
self.next.take().map(|mut block| {
self.next = block.next();
block
})
}
}
I'm having a hard time applying this to the original code, because there might be two different lifetimes, one for the iterator and one for the trait.
Answered by u/quixotrykd/:
The compiler seems to be choking here because it doesn't know how the lifetime on &mut self and ThreadIterator relate. As such, it has no way to guarantee that &mut self lives at least as long as the underlying borrow in ThreadIterator. Looking at your code here, that would be line 12 (note I've fixed your mistake in the above link).
You need to tell the compiler that the lifetime on the output ThreadIterator is the same as the input &mut self (or technically that it lasts at least as long, though you very likely want the same lifetime here), otherwise the compiler has no way to ensure that the "self" that's borrowed by &mut self stick around as long as the ThreadIterator's borrow. Looking at the rules for lifetime elision here, we can see that this doesn't apply to your code, and as such, you need to manually specify the lifetime on &mut self (otherwise it generates another, unrelated, anonymous lifetime, as indicated in the compiler's error message).
The fixed code:
pub trait Block<'a> { // Make public to resolve unrelated error
fn next(&mut self) -> Option<&'a mut (dyn Block<'a> + 'a)> {
None
}
}
pub struct Thread<'a> {
head: Box<dyn Block<'a> + 'a>,
}
impl<'a> Thread<'a> {
fn iter_mut(&'a mut self) -> ThreadIterator<'a> { // Add lifetime to &self
ThreadIterator {
next: Some(self.head.as_mut()),
}
}
}
pub struct ThreadIterator<'a> {
next: Option<&'a mut (dyn Block<'a> + 'a)>,
}
impl<'a> Iterator for ThreadIterator<'a> {
type Item = &'a mut (dyn Block<'a> + 'a);
fn next(&mut self) -> Option<&'a mut (dyn Block<'a> + 'a)> {
self.next.take().map(|mut block| {
self.next = block.next();
block
})
}
}

Specify that lifetime of argument lasts for function call

I have a trait with a function that takes a reference to an iterator:
#[derive(Clone)]
struct Dog {
name: &'static str,
}
trait DogListAction<'a, I>
where
I: Iterator<Item = &'a Dog>,
{
fn on_dog_list(&mut self, dog_list: I);
}
struct DogListActionExample {}
impl<'a, I> DogListAction<'a, I> for DogListActionExample
where
I: Iterator<Item = &'a Dog>,
{
fn on_dog_list(&mut self, dog_list: I) {
for dog in dog_list {
println!("{}", dog.name);
}
}
}
fn main() {
let dogs = vec![Dog { name: "Pluto" }, Dog { name: "Lilly" }];
let mut action_example = DogListActionExample {};
let mut dog_list_actions: Vec<Box<DogListAction<_>>> = vec![Box::new(action_example)];
loop {
let dog_clone = dogs.clone();
for dog_list_action in &mut dog_list_actions {
dog_list_action.on_dog_list(dog_clone.iter());
}
}
}
playground
It does not take any reference to the elements, so there is no need for it to last for more time than the function call.
Due to my limited understanding of lifetimes, I do not know yet how to express this. Calling this function causes a compilation error:
error[E0597]: `dog_clone` does not live long enough
--> src/main.rs:33:41
|
33 | dog_list_action.on_dog_list(dog_clone.iter());
| ^^^^^^^^^ borrowed value does not live long enough
34 | }
35 | }
| - `dog_clone` dropped here while still borrowed
36 | }
| - borrowed value needs to live until here
I guess the borrow checker thinks that data in dog_clone may be referenced after the function ends, but this is not the case.
The problem here is that the code can potentially save short-lived references to dog_clone elements in the longer-lived dog_list_actions. We need to tell the compiler that we will not be saving references the iterator produces. It can be done like this:
trait DogListAction {
fn on_dog_list<'a, I>(&'a mut self, dog_list: I)
where
I: Iterator<Item = &'a Dog>;
}
Now Item's can live for the duration of on_dog_list call. In the original code they must live for longer duration.
But this code creates another problem: we can't box the trait DogListAction anymore as it includes generic function. The usual approach here is to use a trait object:
trait DogListAction {
fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>);
}
Note the second 'a in Box<dyn Iterator<Item = &'a Dog> + 'a>. Rust adds a 'static trait bound to boxed trait objects by default and we don't want 'static here.
#[derive(Clone)]
struct Dog {
name: &'static str,
}
trait DogListAction {
fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>);
}
struct DogListActionExample {}
impl DogListAction for DogListActionExample {
fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>) {
for dog in dog_list {
println!("{}", dog.name);
}
}
}
fn main() {
let dogs = vec![Dog { name: "Pluto" }, Dog { name: "Lilly" }];
let action_example = DogListActionExample {};
let mut dog_list_actions: Vec<Box<DogListAction>> = vec![Box::new(action_example)];
{
let dogs_clone = dogs.clone();
for dog_list_action in &mut dog_list_actions {
dog_list_action.on_dog_list(Box::new(dogs_clone.iter()));
}
}
}
Playground

Why does one non-consuming builder compile while another does not?

I read the builder pattern and then tried to build 2 different builders (Header and Request) as follows:
use std::ascii::AsciiExt;
#[derive(PartialEq, Debug)]
pub struct Headers<'a> (pub Vec<(&'a str, String)>);
impl<'a> Headers<'a> {
pub fn replace(&'a mut self, name: &'a str, value:&str) -> &mut Headers<'a> {
self.0.retain(|&(key, _)|!name.eq_ignore_ascii_case(key));
self.0.push((name, value.to_string()));
self
}
}
#[derive(PartialEq, Debug)]
pub struct Request<'a> {
pub headers: Headers<'a>,
}
impl<'a> Request<'a> {
pub fn header(&'a mut self, name: &'a str, value:&'a str) -> &mut Request<'a> {
self.headers.replace(name, value);
self
}
}
Why does Header compile fine but Request fails with:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/api.rs:154:9
|
153 | self.headers.replace(name, value);
| ------------ first mutable borrow occurs here
154 | self
| ^^^^ second mutable borrow occurs here
155 | }
| - first borrow ends here
You have an issue with your lifetimes: you are re-using the same lifetime ('a) for too many different things, so that when the compiler attempts to use a single lifetime for all those 'a you get a confusing error message.
The solution is simple: do not use 'a everywhere you can put a lifetime, but only where it's necessary.
It is unnecessary to use &'a mut self, the instance (self) does not need to have the same lifetime as the &str it contains! (and actually, cannot really):
impl<'a> Headers<'a> {
pub fn replace(&mut self, name: &'a str, value: &str) -> &mut Headers<'a> {
self.0.retain(|&(key, _)|!name.eq_ignore_ascii_case(key));
self.0.push((name, value.to_string()));
self
}
}
impl<'a> Request<'a> {
pub fn header(&mut self, name: &'a str, value: &str) -> &mut Request<'a> {
self.headers.replace(name, value);
self
}
}

Resources