Here's the code so far, the relevant lines are 27 and 28: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=37bba701ad2e9d47741da1149881ddd1
Error message:
error[E0597]: `neighs` does not live long enough
--> src/lib.rs:28:25
|
17 | while let Some(Reverse(current)) = open.pop() {
| ---------- borrow later used here
...
28 | for neighbor in neighs.iter_mut() {
| ^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
...
38 | }
| - `neighs` dropped here while still borrowed
I used Rust a few times in the past, and I'm fully aware of how basic this problem should be. I've also spent hours trying different things and googling similar problems. I just can't seem to find a solution. How do I make neighs live as long as function a_star?
I would suggest:
Store copies of Cell in open instead of references to Cell
open.push(Reverse(start.clone()));
Make the parent field of the Cell struct a Box or Rc instead of reference:
#[derive(Clone, Eq)]
pub struct Cell {
coords: (u32, u32),
g_cost: u32,
h_cost: u32,
parent: Option<std::rc::Rc<Cell>>,
}
This way open will not reference any of neighs elements or current. which will avoid lifetime issues.
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.
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.
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.
This question already has answers here:
Cannot borrow `x` as mutable more than once at a time
(2 answers)
cannot borrow `rdr` as mutable more than once at a time [when using library from cargo]
(1 answer)
Why do I get the error "cannot borrow x as mutable more than once"?
(2 answers)
Closed 3 years ago.
I am learning Rust by exercise. In this file the goal is to update cells as in a spreadsheet: when a value changes, all cells that are derived from it have to be recalculated. Here, those are called that cell's parents.
Updating a cell value proves no problem, but updating the parents gets me fighting the borrow checker. When I have retrieved the cell from a HashMap and updated the value, I no longer need a mutable reference - so I tried wrapping it in an immutable reference instead. That way I only have to find it once.
But it seems Rust figures since I originally got my immutable reference from a borrowed &mut self, it must still be tied to it. This obviously prevents me from reusing self a second time.
use std::collections::HashMap;
use std::vec::Vec;
struct Cell {
value: i32,
parents: Vec<u32>,
}
pub struct Sheet {
table: HashMap<u32, Cell>,
}
impl Sheet {
pub fn set_value(&mut self, identifier: u32, new_value: i32) {
let mut updated_cell: Option<&Cell> = None;
if let Some(cell) = self.table.get_mut(&identifier) {
let Cell { value, .. } = cell;
*value = new_value;
updated_cell = Some(cell);
}
if let Some(cell) = updated_cell {
recalculate(self, &cell.parents);
}
}
}
fn recalculate(_sheet: &mut Sheet, _cells: &[u32]) {}
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/lib.rs:20:16
|
16 | if let Some(cell) = self.table.get_mut(&identifier) {
| ---------- first mutable borrow occurs here
...
22 | recalculate(self, &cell.parents);
| ^^^^ ------------- first borrow later used here
| |
| second mutable borrow occurs here
I want to know if there is a solution which avoids searching a second time or taking an unnecessary vector copy. I have tried to adjust the code many times, but not all of the syntax is yet clear to me yet.
Rust is protecting you from a potentially dangerous situation. There is nothing in recalculate's signature to guarantee that it won't mutate sheet in such at way that the references in cells become invalid. For example recalculate could delete some cells and then the references in cell.parents would be dangling pointers.
You probably need to pass a clone of the parent cells instead:
if let Some(cell) = updated_cell {
let parents = cell.parents.clone();
recalculate(self, &parents);
}
Alternatively, you may need to consider a different data model, which separates the mutability of individual cells from the mutability of the overall structure. For example, you could wrap cells in a std::cell::Cell or std::cell::RefCell, and pass an immutable reference to the Sheet.
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.