I'm trying to write a tree in rust, here is the Node:
#[derive(Debug)]
struct Node<'a> {
player_id: i8,
visits : i32,
score : i32,
children : Vec<Node<'a>>,
parent: Option<&'a mut Node<'a>>,
action: usize,
}
impl Node<'_> {
pub fn is_leaf(&self) -> bool {
return self.children.is_empty()
}
}
I am trying to add children for every move possible in game:
fn expand_children <'a>(node: & 'a mut Node<'a>, game : &GameState) {
game.legal_moves().iter().for_each(
|action|
node.children.push(
Node::<'a> {
parent: Some(node),
action : *action,
player_id: game.curr_player(),
visits: 0,
score: 0,
children: vec![]
}
)
)
}
This is the error I get:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/MCTS.rs:59:25
|
59 | parent: Some(node),
| ^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
--> src/MCTS.rs:56:9
|
56 | / |action|
57 | | node.children.push(
58 | | Node::<'a> {
59 | | parent: Some(node),
... |
65 | | }
66 | | )
| |_________^
note: ...so that closure can access `node`
--> src/MCTS.rs:59:30
|
59 | parent: Some(node),
| ^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/MCTS.rs:54:21
|
54 | fn expand_children <'a>(node: & 'a mut Node<'a>, game : &GameState) {
| ^^
note: ...so that the expression is assignable
--> src/MCTS.rs:59:25
|
59 | parent: Some(node),
| ^^^^^^^^^^
= note: expected `Option<&'a mut Node<'a>>`
found `Option<&mut Node<'a>>`
I thought I did set the lifetime of node as 'a in the function parameters as its &'a mut Node<'a>. How is it possible that the compiler does not find it on compiletime? Or am I missing something.. I know that the error message should tell me whats wrong but I dont think I understand it very well..
How is it possible that the compiler does not find it on compiletime?
The compiler did find it, and it found it unsatisfactory. And the compiler is right ;)
To understand the deeper background, I strongly advice reading:
https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
Why can't I store a value and a reference to that value in the same struct?
https://rust-unofficial.github.io/too-many-lists/
I will briefly try to explain the problem. If you don't understand parts of what I say, please read at least the chapter in the Rust book, it really does explain a lot about how references work.
The main problem is you cannot set the lifetime of an object via lifetime annotation. You can only describe how long it lives, but you cannot change it. An item lives until it doesn't. A reference does not keep an object alive, the lifetime annotation on it only specifies how long an object stored in it must be alive so it can be stored in it in the first place.
Further, only one mutable reference to an object may exist at any time.
With that knowledge you can probably already kind of see why parent: Option<&'a mut Node<'a>> is a problem. First, assuming you have more than one child, there are already multiple mutable references to the parent node, which can't be.
Second, the fact that the parent stores the children, and the children contain a reference to the parent forms a circular reference. Circular references are almost impossible in safe Rust. To know more about why, read the second and the third link.
So first off: don't use references in this case. Go one level higher and use smart pointers / refcounters. Maybe use Rc/Arc combined with Weak in the reverse direction (to avoid circular references; although if possible just avoid the reverse direction entirely). Further, you will need RefCell/Mutex for interiour mutability, as both Rc/Arc only expose immutable objects.
But again, look at the too-many-lists link, those problems are described there in great detail.
Related
I'm trying to iterate over a deepening finite state space while maintaining a set of seen states. The following function is incomplete, but defined enough to demonstrate the problem I'm having.
fn get_possible_final_results(&self, mut seen: BTreeSet<ValveState>) -> Vec<u16> {
if self.is_done() {
return vec![self.result];
}
let mut successors = self.get_successors();
let mut results = Vec::new();
while !successors.is_empty() {
let successor = successors.pop().unwrap();
if seen.contains(&successor) {
continue;
}
let new_successors = successor.get_successors();
successors.extend(new_successors);
seen.insert(successor);
}
return results;
}
Here's the signature of get_successors. Returned ValveStates don't reference self (or at least they shouldn't).
fn get_successors(&self) -> Vec<ValveState>
The compiler implies that successor is borrowed beyond the length of a method call at some point, but I don't understand how or why.
error[E0597]: `successor` does not live long enough
--> src\main.rs:78:34
|
67 | fn get_possible_final_results(&self, mut seen: BTreeSet<ValveState>) -> Vec<u16> {
| -------- has type `BTreeSet<ValveState<'2>>`
...
78 | let new_successors = successor.get_successors();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
79 | successors.extend(new_successors);
80 | seen.insert(successor);
| ---------------------- argument requires that `successor` is borrowed for `'2`
81 | }
| - `successor` dropped here while still borrowed
Shouldn't the call the get_successors only borrow successor for the duration of that method call? Am I misunderstanding the problem?
I've tried introducing various lifetimes (which I'm still getting a handle on) to no avail. I've also tried searching for this error elsewhere, and I'm sure it's out there, but I've been unable to find an explanation that addresses this specific situation.
As you can probably tell, I'm still getting used to Rust. Any help is appreciated, even if you have to explain it like I'm five years old. Thanks!
Here's more information about ValveState and how it's constructed in get_successors:
struct ValveState<'a> {
network: &'a ValveNetwork<'a>,
player_position: &'a str,
open_valves: BTreeSet<&'a Valve<'a>>,
steps_left: u16,
result: u16
}
An example of a ValveState being constructed in get_successors:
let new_state = ValveState {
network: self.network,
player_position: self.player_position,
open_valves: self.open_valves.clone(),
steps_left: self.steps_left - 1,
result: self.result+ self.get_step_result()
};
successors.push(new_state);
return successors;
#eggyal's second comment clued me in on the issue. I had previously only tried defining an 'a lifetime in ValveState function declarations, rather than as in impl<'a> ValveState<'a>. I clearly need to solidify my understanding of what the differences between these things are, thanks for the correction.
tl;dr blocked by "argument requires that `x` is borrowed for `'y`"; how can I coerce variable x to lifetime 'y?
Given the following code, I'm blocked when trying to create the Box pointer pointing to a reference. I know the referenced object instance lives long enough. However, the rust compiler is concerned it does not.
How do I tell the rust compiler that Box::new(&thing) is valid for the lifetime of the containing struct instance?
Code example
This code is essentially:
Things (a Vec), holding multiple Things
counter of Things (a HashMap), holding multiple Box pointers to different &Thing as keys, a u64 count as values
(My best attempt at) a minimal example (rust playground):
use std::collections::HashMap;
type Thing<'a> = (&'a str, usize);
type Things<'a> = Vec<Thing<'a>>;
type ThingsCounterKey<'a> = Box<&'a Thing<'a>>;
type ThingsCounter<'a> = HashMap<ThingsCounterKey<'a>, u64>;
pub struct Struct1<'struct1> {
things1: Things<'struct1>,
thingscounter1: ThingsCounter<'struct1>,
}
impl<'struct1> Struct1<'struct1> {
pub fn new() -> Struct1<'struct1> {
Struct1{
things1: Things::new(),
thingscounter1: ThingsCounter::new(),
}
}
fn things_update(&mut self, thing_: Thing<'struct1>) {
self.things1.push(thing_);
let counter = self.thingscounter1.entry(
ThingsCounterKey::new(&thing_)
).or_insert(0);
*counter += 1;
}
}
fn main() {
let mut s1 = Struct1::new();
for (x, y) in [("a", 1 as usize), ("b", 2 as usize)] {
s1.things_update((x, y));
}
}
This results in compiler error:
error[E0597]: `thing_` does not live long enough
--> src/main.rs:24:35
|
14 | impl<'struct1> Struct1<'struct1> {
| -------- lifetime `'struct1` defined here
...
24 | ThingsCounterKey::new(&thing_)
| ----------------------^^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `thing_` is borrowed for `'struct1`
...
27 | }
| - `thing_` dropped here while still borrowed
For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` due to previous error
How can I tell the rust compiler "&thing_ has the lifetime of 'struct1"?
Similar questions
Before this Question is marked as duplicate, these questions are similar but not quite the same. These Questions address 'static lifetimes or other slightly different scenarios.
Argument requires that value is borrowed for 'static not working for non copy value
Argument requires that _ is borrowed for 'static - how do I work round this?
"argument requires that record is borrowed for 'static" when using belonging_to associations with tokio-diesel
(tokio::spawn) borrowed value does not live long enough -- argument requires that sleepy is borrowed for 'static
Rust lifetime syntax when borrowing variables
Borrow data out of a mutex "borrowed value does not live long enough"
Rust: argument requires that borrow lasts for 'static
thing_ is passed by value. Its lifetime ends at the end of things_update. That means, the reference to thing_ becomes invalid after the end of the function but still be held by the struct, which is certainly should be rejected.
Like many times, actually the compiler is right and you were wrong. The compiler prevented you from use-after-free.
thing_ doesn't live long enough: you pushed a copy of it into the vector. It was clear if you'd used a type that isn't Copy:
type Thing<'a> = (&'a str, String);
// ...
Besides the previous error, now you also get:
error[E0382]: borrow of moved value: `thing_`
--> src/main.rs:24:35
|
21 | fn things_update(&mut self, thing_: Thing<'struct1>) {
| ------ move occurs because `thing_` has type `(&str, String)`, which does not implement the `Copy` trait
22 | self.things1.push(thing_);
| ------ value moved here
23 | let counter = self.thingscounter1.entry(
24 | ThingsCounterKey::new(&thing_)
| ^^^^^^^ value borrowed here after move
Playground.
In other case, you would have to first push the item into the vector and then retrieve a reference to the pushed item there, like:
self.things1.push(thing_);
let counter = self.thingscounter1.entry(
ThingsCounterKey::new(self.things1.last().unwrap())
).or_insert(0);
But in this case it will not work, and you'll get a long "cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements" error. This is because you're essentially trying to do the impossible: create a self-referential struct. See Why can't I store a value and a reference to that value in the same struct? for more about this problem and how to solve it.
I'm getting
error[E0373]: closure may outlive the current function, but it borrows row_nr, which is owned by the current function
I would not expect this, since row_nr is a u32, so I'd expect it to be copied rather than moved:
fn get_neighbours(values: &Vec<Vec<u32>>, row: usize, col: usize) -> Vec<u32> {
vec![
values.get(row - 1).and_then(|cols| cols.get(col)),
values.get(row).and_then(|cols| cols.get(col - 1)),
values.get(row).and_then(|cols| cols.get(col + 1)),
values.get(row + 1).and_then(|cols| cols.get(col)),
].into_iter().filter_map(|value_opt| value_opt.map(|value| *value)).collect()
}
fn get_points(values: Vec<Vec<u32>>) -> Vec<(u32, Vec<u32>)> {
values
.iter()
.enumerate()
.flat_map(|(row_nr, columns)| {
columns.iter().enumerate().map(|(column_nr, height)| {
let neighbours = get_neighbours(&values, row_nr, column_nr);
(*height, neighbours)
})
}).collect()
}
Full error message:
--> src/lib.rs:16:44
|
16 | columns.iter().enumerate().map(|(column_nr, height)| {
| ^^^^^^^^^^^^^^^^^^^^^ may outlive borrowed value `row_nr`
17 | let neighbours = get_neighbours(&values, row_nr, column_nr);
| ------ `row_nr` is borrowed here
|
note: closure is returned here
--> src/lib.rs:16:13
|
16 | / columns.iter().enumerate().map(|(column_nr, height)| {
17 | | let neighbours = get_neighbours(&values, row_nr, column_nr);
18 | | (*height, neighbours)
19 | | })
| |______________^
help: to force the closure to take ownership of `row_nr` (and any other referenced variables), use the `move` keyword
|
16 | columns.iter().enumerate().map(move |(column_nr, height)| {
| ++++
See also on the Rust playground.
Now, the error suggest using move, but that becomes problematic because I'd only like to pass a reference to the values Vec (which I don't think should outlive the closure, because get_neighbours takes u32s from that Vec and thus should make copies too, I think?).
I presume I'm misunderstanding lifetimes here. I'd appreciate any insights on what I'm misinterpreting. I looked at a couple of related questions, but they seem to either resolve it using a move (which, as mentioned above, I think I should (be able to) avoid?), or have multiple borrow checker issues, making it hard for me to understand which applies ones to me (e.g. this answer).
I would not expect this, since row_nr is a u32, so I'd expect it to be copied rather than moved
This expectation is correct, assuming it were moved in the first place. In this case it's not moved, it's borrowed, because by default closures borrow values from their environment. To request a move, which will for u32 indeed result in a copy, you need to use the move keyword explicitly.
As you discovered, when you just use move, you also move values, which doesn't compile and is anyway not what you want. The standard Rust idiom to move only one value into the closure is to use move and explicitly borrow the captured variables you don't want moved (in yout case values). For example, this compiles:
.flat_map(|(row_nr, columns)| {
columns.iter().enumerate().map({
let values = &values;
move |(column_nr, height)| {
let neighbours = get_neighbours(values, row_nr, column_nr);
(*height, neighbours)
}
})
})
Playground
As for your titular question of why may a closure outlive the current function: Note that the "current function" in the error message refers to the outer closure, the one passed to flat_map(). Since the inner closure becomes part of the iterator returned by map(), and the outer closure immediately returns that iterator, it is trivially true that the inner closure does outlive the "current function" and that it cannot be allowed to borrow either row_nr or columns. (But borrowing values is perfectly fine because values outlives both closures.)
I have the following code which you can also see in the playground:
struct Node<'a> {
parent: Option<&'a Node<'a>>,
name: &'a str,
}
fn looper(nodes: &mut Vec<Node>) {
for i in 0..nodes.len() {
let n = &nodes[i];
let next_node = Node {
parent: Some(n),
name: "please compile",
};
nodes.push(next_node);
}
}
It's supposed to take a Vec of Nodes and append Nodes to it that reference the Nodes already in the Vec. Unfortunately I get this error:
error[E0623]: lifetime mismatch
--> src/main.rs:13:20
|
6 | fn looper(nodes: &mut Vec<Node>) {
| -------------- these two types are declared with different lifetimes...
...
13 | nodes.push(next_node);
| ^^^^^^^^^ ...but data from `nodes` flows into `nodes` here
How can I make this compile? An explanation of how to think about lifetimes in this context would be useful. I understand this may be an issue due to variance but am not sure how to rephrase my problem to give me the functionality I would like.
A general rule: when some value's type, or trait it implements, has a lifetime parameter, that lifetime is always longer than the life of the value itself — the value has a guarantee that the references it contains won't go invalid before they are dropped.
In fact, in your example we can see that if this were not the case, the lifetime checking would be unsound; you're adding values to nodes, but nothing would prevent looper from instead removing values from nodes, which would then invalidate any parent references that referred to those values.
The only practical way to build a tree or linked list of references (without special-purpose unsafe code that has a particular plan to keep things sound) is to write a recursive function; each function call frame may refer to nodes constructed by its caller (and its caller's caller and so on). This is accepted by the borrow checker because each frame has its own new, shorter lifetime for the references (a reference can always be taken as having a shorter lifetime than it started with).
I'm learning Rust and tried coding a doubly-linked list. However, I'm stuck already at a typical iterative traversal implementation. I'm getting the impression that the borrow checker / drop checker is too strict and cannot infer the correct lifetime for the borrow when it crosses the function boundary from RefCell. I need to repeatedly set a variable binding (curr in this case) to the borrow of its current contents:
use std::cell::RefCell;
use std::rc::Rc;
pub struct LinkedList<T> {
head: Option<Rc<RefCell<LinkedNode<T>>>>,
// ...
}
struct LinkedNode<T> {
value: T,
next: Option<Rc<RefCell<LinkedNode<T>>>>,
// ...
}
impl<T> LinkedList<T> {
pub fn insert(&mut self, value: T, idx: usize) -> &mut LinkedList<T> {
// ... some logic ...
// This is the traversal that fails to compile.
let mut curr = self.head.as_ref().unwrap();
for _ in 1..idx {
curr = curr.borrow().next.as_ref().unwrap()
}
// I want to use curr here.
// ...
unimplemented!()
}
}
The compiler complains:
Without NLL
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:22:20
|
22 | curr = curr.borrow().next.as_ref().unwrap()
| ^^^^^^^^^^^^^ temporary value does not live long enough
23 | }
| - temporary value dropped here while still borrowed
...
28 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
With NLL
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:22:20
|
22 | curr = curr.borrow().next.as_ref().unwrap()
| ^^^^^^^^^^^^^
| |
| creates a temporary which is freed while still in use
| a temporary with access to the borrow is created here ...
23 | }
| -
| |
| temporary value is freed at the end of this statement
| ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, LinkedNode<T>>`
|
= note: consider using a `let` binding to create a longer lived value
= note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped.
I would really appreciate a iterative solution (non-recursive) to this problem.
You can clone Rc to avoid lifetime issues:
let mut curr = self.head.as_ref().unwrap().clone();
for _ in 1..idx {
let t = curr.borrow().next.as_ref().unwrap().clone();
curr = t;
}
Here's a smaller reproduction that I believe shows the same problem:
use std::cell::RefCell;
fn main() {
let foo = RefCell::new(Some(42));
let x = foo.borrow().as_ref().unwrap();
}
As I read it:
foo.borrow() returns a cell::Ref, a type of smart pointer. In this case, the smart pointer acts like an &Option<i32>.
as_ref() creates an Option<&i32> where the inner reference has the same lifetime as the smart pointer.
The Option is discarded, yielding only an &i32, still with a lifetime of the smart pointer.
Notably, the smart pointer Ref only lasts for the statement, but the code attempts to return a reference into the Ref that would outlive the statement.
Generally, the solution would be to do something like this:
let foo_borrow = foo.borrow();
let x = foo_borrow.as_ref().unwrap();
This keeps the smart pointer around longer, allowing the lifetime of the reference to be valid for as long as foo_borrow (representing the borrow itself) exists.
In the case of a loop, there's not much you can do, as you essentially want to borrow every previous node until you get to the next one.