This question already has answers here:
How do I express mutually recursive data structures in safe Rust?
(4 answers)
Closed 4 years ago.
I have a structure with a parent property I want to add to a queue. The parent is the same type as itself, so I need to wrap it in a Box.
use std::collections::vec_deque::VecDeque;
struct GraphNode {
value: u32,
parent: Option<Box<&GraphNode>>,
}
fn main() {
let mut queue: VecDeque<GraphNode> = VecDeque::new();
let parent = GraphNode {
value: 23,
parent: Option::None,
};
let second = GraphNode { value: 42, parent };
let third = GraphNode {
value: 19,
parent: Option::Some(Box::from(&parent)),
};
queue.push_front(parent);
queue.push_front(second);
queue.push_front(third);
}
Playground
error[E0106]: missing lifetime specifier
--> src/main.rs:5:24
|
5 | parent: Option<Box<&GraphNode>>,
| ^ expected lifetime paramete
The parent can be null, so I get that it needs to be Box<Option<&GraphNode>>, but I get the error expected lifetime parameter, however what's in the docs isn't really making sense to me.
There's also the issue that when I create a Box, to save to the parent, the value is moved. I don't want to move the value, I just want to save a reference in the box.
I think you are looking for std::rc::Rc, not Box.
use std::collections::vec_deque::VecDeque;
use std::rc::Rc;
struct GraphNode {
value: u32,
parent: Option<Rc<GraphNode>>,
}
fn main() {
let mut queue: VecDeque<Rc<GraphNode>> = VecDeque::new();
let parent = Rc::new(GraphNode {
value: 23,
parent: None,
});
let second = Rc::new(GraphNode {
value: 42,
parent: None,
});
let third = Rc::new(GraphNode {
value: 19,
parent: Some(parent.clone()), // Clones the reference, still point to the same thing.
});
queue.push_front(parent);
queue.push_front(second);
queue.push_front(third);
}
Playground
Rc (reference counted), is a way to have multiple "owners" to the same object. When cloning, you are just cloning the reference, so changes made to either one will affect the other.
The lifetime problems you encountered is because you are storing a direct reference (don't actually know what it's suppose to be called) made with &.
If you want to know more about lifetimes, here's the entry from the book.
Related
I am trying to implement Red-Black Tree in Rust. After 2 days of battling with the compiler, I am ready to give up and am here asking for help.
This question helped me quite a bit: How do I handle/circumvent "Cannot assign to ... which is behind a & reference" in Rust?
I looked at existing sample code for RB-Trees in Rust, but all of the ones I saw use some form of unsafe operations or null, which we are not supposed to use here.
I have the following code:
#[derive(Debug, Clone, PartialEq)]
pub enum Colour {
Red,
Black,
}
type T_Node<T> = Option<Box<Node<T>>>;
#[derive(Debug, Clone, PartialEq)]
pub struct Node<T: Copy + Clone + Ord> {
value: T,
colour: Colour,
parent: T_Node<T>,
left: T_Node<T>,
right: T_Node<T>,
}
impl<T: Copy + Clone + Ord> Node<T>
{
pub fn new(value: T) -> Node<T>
{
Node {
value: value,
colour: Colour::Red, // add a new node as red, then fix violations
parent: None,
left: None,
right: None,
// height: 1,
}
}
pub fn insert(&mut self, value: T)
{
if self.value == value
{
return;
}
let mut leaf = if value < self.value { &mut self.left } else { &mut self.right };
match leaf
{
None =>
{
let mut new_node = Node::new(value);
new_node.parent = Some(Box::new(self));
new_node.colour = Colour::Red;
(*leaf) = Some(Box::new(new_node));
},
Some(ref mut leaf) =>
{
leaf.insert(value);
}
};
}
}
The line new_node.parent = Some(Box::new(self)); gives me the error.
I understand understand why the error happens (self is declared as a mutable reference) and I have no idea how to fix this, but I need self to be a mutable reference so I can modify my tree (unless you can suggest something better).
I tried to declare the T_Node to have a mutable reference instead of just Node, but that just created more problems.
I am also open to suggestions for a better choice of variable types and what not.
Any help is appreciated.
There are some faults in the design which makes it impossible to go any further without making some changes.
First, Box doesn't support shared ownership but you require that because the same node is referenced by parent (rbtree.right/rbtree.left) and child (rbtree.parent). For that you need Rc.
So instead of Box, you will need to switch to Rc:
type T_Node<T> = Option<Rc<Node<T>>>;
But this doesn't solve the problem. Now your node is inside Rc and Rc doesn't allow mutation to it's contents (you can mutate by get_mut but that requires it to be unique which is not a constant in your case). You won't be able to do much with your tree unless you can mutate a node.
So you need to use interior mutability pattern. For that we will add an additional layer of RefCell.
type T_Node<T> = Option<Rc<RefCell<Node<T>>>>;
Now, this will allow us to mutate the contents inside.
But this doesn't solve it. Because you need to hold a reference from the child to the parent as well, you will end up creating a reference cycle.
Luckily, the rust book explains how to fix reference cycle for the exact same scenario:
To make the child node aware of its parent, we need to add a parent field to our Node struct definition. The trouble is in deciding what the type of parent should be. We know it can’t contain an Rc, because that would create a reference cycle with leaf.parent pointing to branch and branch.children pointing to leaf, which would cause their strong_count values to never be 0. Thinking about the relationships another way, a parent node should own its children: if a parent node is dropped, its child nodes should be dropped as well. However, a child should not own its parent: if we drop a child node, the parent should still exist. This is a case for weak references!
So we need child to hold a weak reference to parent. This can be done as:
type Child<T> = Option<Rc<RefCell<Node<T>>>>;
type Parent<T> = Option<Weak<RefCell<Node<T>>>>;
Now we have fixed majority of the design.
One more thing that we should do is, instead of exposing Node directly, we will encapsulate it in a struct RBTree which will hold the root of the tree and operations like insert, search, delete, etc. can be called on RBtree. This will make things simple and implementation will become more logical.
pub struct RBTree<T: Ord> {
root: Child<T>,
}
Now, let's write an insert implementation similar to yours:
impl<T: Ord> RBTree<T> {
pub fn insert(&mut self, value: T) {
fn insert<T: Ord>(child: &mut Child<T>, mut new_node: Node<T>) {
let child = child.as_ref().unwrap();
let mut child_mut_borrow = child.borrow_mut();
if child_mut_borrow.value == new_node.value {
return;
}
let leaf = if child_mut_borrow.value > new_node.value {
&mut child_mut_borrow.left
} else {
&mut child_mut_borrow.right
};
match leaf {
Some(_) => {
insert(leaf, new_node);
}
None => {
new_node.parent = Some(Rc::downgrade(&child));
*leaf = Some(Rc::new(RefCell::new(new_node)));
}
};
}
let mut new_node = Node::new(value);
if self.root.is_none() {
new_node.parent = None;
self.root = Some(Rc::new(RefCell::new(new_node)));
} else {
// We ensure that a `None` is never sent to insert()
insert(&mut self.root, new_node);
}
}
}
I defined an insert function inside the RBTree::insert just for the sake of simplicity of recursive calls. The outer functions tests for root and further insertions are carried out inside nested insert functions.
Basically, we start with:
let mut new_node = Node::new(value);
This creates a new node.
Then,
if self.root.is_none() {
new_node.parent = None;
self.root = Some(Rc::new(RefCell::new(new_node)));
} else {
// We ensure that a `None` is never sent to insert()
insert(&mut self.root, new_node);
}
If root is None, insert at root, otherwise call insert with root itself. So the nested insert function basically receives the parent in which left and right child are checked and the insertion is made.
Then, the control moves to the nested insert function.
We define the following two lines for making it convenient to access inner data:
let child = child.as_ref().unwrap();
let mut child_mut_borrow = child.borrow_mut();
Just like in your implementation, we return if value is already there:
if child_mut_borrow.value == new_node.value {
return;
}
Now we store a mutable reference to either left or right child:
let leaf = if child_mut_borrow.value > new_node.value {
&mut child_mut_borrow.left
} else {
&mut child_mut_borrow.right
};
Now, a check is made on the child if it is None or Some. In case of None, we make the insertion. Otherwise, we call insert recursively:
match leaf {
Some(_) => {
insert(leaf, new_node);
}
None => {
new_node.parent = Some(Rc::downgrade(&child));
*leaf = Some(Rc::new(RefCell::new(new_node)));
}
};
Rc::downgrade(&child) is for generating a weak reference.
Here is a working sample: Playground
This question already has answers here:
What do I have to do to solve a "use of moved value" error?
(3 answers)
What types are valid for the `self` parameter of a method?
(2 answers)
Closed 3 years ago.
It seems to be fine to modify a vector on its own, but as soon as it is wrapped in a struct, it can not be mutated by a method on the struct.
I've created a very simplified version of my use case below, in two versions, one with just a vector, and one with a struct.
Why is it that this code is fine:
struct Task {
foo: String,
}
fn main() {
let mut list_of_tasks = Vec::new();
loop {
list_of_tasks.push(Task {
foo: String::from("bar"),
});
}
}
But this is not:
struct Task {
foo: String,
}
struct ListOfTasks(pub Vec<Task>);
impl ListOfTasks {
fn push(mut self, task: Task) {
self.0.push(task);
}
}
fn main() {
let list_of_tasks = ListOfTasks(Vec::new());
loop {
list_of_tasks.push(Task {
foo: String::from("bar"),
});
}
}
The second example fails with:
error[E0382]: use of moved value: `list_of_tasks`
--> src/main.rs:17:9
|
14 | let list_of_tasks = ListOfTasks(Vec::new());
| ------------- move occurs because `list_of_tasks` has type `ListOfTasks`, which does not implement the `Copy` trait
...
17 | list_of_tasks.push(Task {
| ^^^^^^^^^^^^^ value moved here, in previous iteration of loop
I think I'm not understanding something about moving a struct that uses mut self, but can't find any obvious examples online of how to approach this.
I'm doing Advent Of Code Day 7 in Rust. I have to parse a tree out of order like so:
a(10)
c(5) -> a, b
b(20)
That says c is the root with a and b as its children.
I handle this by parsing each line, making an object, and storing it in a hash by name. If it shows up later as a child, like a, I can use that hash to lookup the object and apply it as a child. If it shows up as a child before being defined, like b, I can create a partial version and update it via the hash. The above would be something like:
let mut np = NodeParser{
map: HashMap::new(),
root: None,
};
{
// This would be the result of parsing "a(10)".
{
let a = Node{
name: "a".to_string(),
weight: Some(10),
children: None
};
np.map.insert( a.name.clone(), a );
}
// This is the result of parsing "c(5) -> a, b".
// Note that it creates 'b' with incomplete data.
{
let b = Node{
name: "b".to_string(),
weight: None,
children: None
};
np.map.insert("b".to_string(), b);
let c = Node{
name: "c".to_string(),
weight: Some(5),
children: Some(vec![
*np.map.get("a").unwrap(),
// ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
*np.map.get("b").unwrap()
// ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
])
};
np.map.insert( c.name.clone(), c );
}
// Parsing "b(20)", it's already seen b, so it updates it.
// This also updates the entry in c.children. It avoids
// having to search all nodes for any with b as a child.
{
let mut b = np.map.get_mut( "b" ).unwrap();
b.weight = Some(20);
}
}
I might want to look up a node and look at its children.
// And if I wanted to look at the children of c...
let node = np.map.get("c").unwrap();
for child in node.children.unwrap() {
// ^^^^ cannot move out of borrowed content
println!("{:?}", child);
}
Rust does not like this. It doesn't like that both NodeParser.map and Node.children own a node.
error[E0507]: cannot move out of borrowed content
--> /Users/schwern/tmp/test.rs:46:21
|
46 | *np.map.get("a").unwrap(),
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
error[E0507]: cannot move out of borrowed content
--> /Users/schwern/tmp/test.rs:49:21
|
49 | *np.map.get("b").unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
It doesn't like that the for loop is trying to borrow the node to iterate because I've already borrowed the node from the NodeParser that owns it.
error[E0507]: cannot move out of borrowed content
--> /Users/schwern/tmp/test.rs:68:18
|
68 | for child in node.children.unwrap() {
| ^^^^ cannot move out of borrowed content
I think I understand what I'm doing wrong, but I'm not sure how to make it right.
How should I construct this to make the borrower happy? Because of the way NodeParser.map and Node.children must be linked, copying is not an option.
Here is the code to test with. In the real code both Node and NodeParser have implementations and methods.
One option is unsafe code ... but I would suggest avoiding that if you're using the Advent of Code to learn idiomatic Rust and not just drop all the safety its trying to give you.
Another option is to reference count the Node instances so that the borrow checker is happy and the compiler knows how to clean things up. The std::rc::Rc type does this for you ... and essentially every call to clone() just increments a reference count and returns a new Rc instance. Then every time an object is dropped, the Drop implementation just decrements the reference count.
As for the iteration .. for x in y is syntactic sugar for for x in y.into_iter(). This is attempting to move the contents of children out of node (notice in the IntoIterator trait, into_iter(self) takes ownership of self). To rectify this, you can ask for a reference instead when iterating, using for x in &y. This essentially becomes for x in y.iter(), which does not move the contents.
Here are these suggestions in action.
use std::collections::HashMap;
use std::rc::Rc;
struct NodeParser {
map: HashMap<String, Rc<Node>>,
root: Option<Node>,
}
#[derive(Debug)]
struct Node {
name: String,
children: Option<Vec<Rc<Node>>>,
}
fn main() {
let mut np = NodeParser{
map: HashMap::new(),
root: None,
};
let a = Rc::new(Node{ name: "a".to_string(), children: None });
np.map.insert( a.name.clone(), a.clone() );
let b = Rc::new(Node{ name: "b".to_string(), children: None });
np.map.insert( b.name.clone(), b.clone() );
let c = Rc::new(Node{
name: "c".to_string(),
children: Some(vec![a, b])
});
np.map.insert( c.name.clone(), c.clone() );
let node = np.map.get("c").unwrap();
for child in &node.children {
println!("{:?}", child);
}
}
EDIT: I will expand on my comment here. You can use lifetimes here too if you want, but I'm concerned that the lifetime solution will work against the MCVE and won't work once applied to the actual problem the OP (not just of this question... others as well) actually has. Lifetimes are tricky in Rust and small things like re-ordering the instantiation of variables to allow the lifetime solution can throw people off. My concern being they will run into lifetime issues and therefore the answers won't be appropriate to their actual situation even if it works for the MCVE. Maybe I overthink that though..
I've been playing with Rust for the past few days,
and I'm still struggling with the memory management (figures).
I wrote a simple project that creates a hierarchy of structs ("keywords") from lexing/parsing a text file.
A keyword is defined like this:
pub struct Keyword<'a> {
name: String,
code: u32,
parent: Option<&'a Keyword<'a>>,
}
which is my equivalent for this C struct:
typedef struct Keyword Keyword;
struct Keyword {
char* name;
unsigned int code;
Keyword* parent;
};
A hierarchy is just a container for keywords, defined like this:
pub struct KeywordHierarchy<'a> {
keywords: Vec<Box<Keyword<'a>>>,
}
impl<'a> KeywordHierarchy<'a> {
fn add_keyword(&mut self, keyword: Box<Keyword<'a>>) {
self.keywords.push(keyword);
}
}
In the parse function (which is a stub of the complete parser), I recreated the condition that spawns the lifetime error in my code.
fn parse<'a>() -> Result<KeywordHierarchy<'a>, String> {
let mut hierarchy = KeywordHierarchy { keywords: Vec::new() };
let mut first_if = true;
let mut second_if = false;
while true {
if first_if {
// All good here.
let root_keyword = Keyword {
name: String::from("ROOT"),
code: 0,
parent: None,
};
hierarchy.add_keyword(Box::new(root_keyword));
first_if = false;
second_if = true;
}
if second_if {
// Hierarchy might have expired here?
// Find parent
match hierarchy.keywords.iter().find(|p| p.code == 0) {
None => return Err(String::from("No such parent")),
Some(parent) => {
// If parent is found, create a child
let child = Keyword {
name: String::from("CHILD"),
code: 1,
parent: Some(&parent),
};
hierarchy.add_keyword(Box::new(child));
}
}
second_if = false;
}
if !first_if && !second_if {
break;
}
}
Ok(hierarchy)
}
There's a while loop that goes through the lexer tokens.
In the first if, I add the ROOT keyword to the hierarchy, which is the only one that doesn't have a parent, and everything goes smoothly as expected.
In the second if, I parse the children keywords and I get a lifetime error when invoking KeywordHierarchy.add_keyword().
hierarchy.keywords` does not live long enough
Could you guys recommend an idiomatic way to fix this?
Cheers.
P.S. Click here for the playground
The immediate problem I can see with your design is that your loop is going to modify the hierarchy.keywords vector (in the first_if block), but it also borrows elements from the hierarchy.keywords vector (in the second_if block).
This is problematic, because modifying a vector may cause its backing buffer to be reallocated, which, if it were allowed, would invalidate all existing borrows to the vector. (And thus it is not allowed.)
Have you considered using an arena to hold your keywords instead of a Vec? Arenas are designed so that you can allocate new things within them while still having outstanding borrows to elements previously allocated within the arena.
Update: Here is a revised version of your code that illustrates using an arena (in this case a rustc_arena::TypedArena, but that's just so I can get this running on the play.rust-lang.org service) alongside a Vec<&Keyword> to handle the lookups.
https://play.rust-lang.org/?gist=fc6d81cb7efa7e4f32c481ab6482e587&version=nightly&backtrace=0
The crucial bits of code are this:
First: the KeywordHierarchy now holds a arena alongside a vec:
pub struct KeywordHierarchy<'a> {
keywords: Vec<&'a Keyword<'a>>,
kw_arena: &'a TypedArena<Keyword<'a>>,
}
Second: Adding a keyword now allocates the spot in the arena, and stashes a reference to that spot in the vec:
fn add_keyword(&mut self, keyword: Keyword<'a>) {
let kw = self.kw_arena.alloc(keyword);
self.keywords.push(kw);
}
Third: the fn parse function now takes an arena (reference) as input, because we need the arena to outlive the stack frame of fn parse:
fn parse<'a>(arena: &'a TypedArena<Keyword<'a>>) -> Result<KeywordHierarchy<'a>, String> {
...
Fourth: To avoid borrow-checker issues with borrowing hierarchy as mutable while also iterating over it, I moved the hierarchy modification outside of your Find parent match:
// Find parent
let parent = match hierarchy.keywords.iter().find(|p| p.code == 0) {
None => return Err(String::from("No such parent")),
Some(parent) => *parent, // (this deref is important)
};
// If parent is found, create a child
let child = Keyword {
name: String::from("CHILD"),
code: 1,
parent: Some(parent),
};
hierarchy.add_keyword(child);
second_if = false;
I want to be able to store a struct called Child inside a Parent, where the Child contains a reference back to the parent.
It works if I have the Child structs directly inside the parent like this:
struct Parent<'s> {
cache: RefCell<Vec<Child<'s>>>
}
But if I move the Vec into a separate struct, then it will fail to compile with lifetime errors.
struct Parent<'s> {
cache: RefCell<Cache<'s>>
}
struct Cache<'s> {
children: Vec<Child<'s>>
}
It is possible to make this example work with the separate structs?
Here's the full working code, which compiles fine. When move the children into the separate struct then it fails.
My analysis of the problem:
When Parent contains children directly, 's is the same lifetime as the scope of the Parent struct itself, thus I can call methods that take &'s self on Parent.
When Parent contains Cache which contains children, 's is the same lifetime as the scope of the Cache struct, which is created before Parent, thus it is impossible to call methods on Parent that take &'s self. Attempting to do so gives the error
<anon>:33:15: 33:16 error: `p` does not live long enough
<anon>:33 let obj = p.create_object();
^
<anon>:30:48: 38:2 note: reference must be valid for the block suffix following statement 0 at 30:47...
<anon>:30 let cache = Cache { children: Vec::new() }; // the lifetime `'s` is essentially from this line to the end of the program
<anon>:31 let mut p = Parent { cache: RefCell::new(cache) }; // although the Parent instance was created here, 's still refers to the lifetime before it
<anon>:32 // this fails because p doesn't live long enough
<anon>:33 let obj = p.create_object();
I need a way of shortening 's to the scope of Parent, not the scope of the Cache.
Disclaimer:
This question is very similar to one I asked earlier (https://stackoverflow.com/questions/32579518/rust-lifetime-error-with-self-referencing-struct?noredirect=1#comment53014063_32579518) that was marked as duplicate. I've read through the answer and I believe I'm beyond that as I can get the lifetimes of references right (as shown in my first example). I'm asking this (now slightly different) question again because I now have a concrete example that works, and one that doesn't work. I'm sure that what can be done with one struct can be done with two, right?
You can make it compile by forcing the Cache and the Parent to have the same lifetime by defining them in the same let binding.
fn main() {
let (cache, mut p);
cache = Cache { children: Vec::new() };
p = Parent { cache: RefCell::new(cache) };
let obj = p.create_object();
let c1 = Child { parent: &p, data: 1 };
p.cache.borrow_mut().children.push(c1);
}
Here, we're essentially declaring a destructured tuple and then initializing it. We cannot initialize the tuple directly on the let binding:
let (cache, mut p) = (Cache { children: Vec::new() }, Parent { cache: RefCell::new(cache) });
because the initializer for p references cache, but that name is not defined until the end of the let statement. The separate initialization works because the compiler tracks which variables are initialized; if you swap the order of the assignments, you'll get a compiler error:
<anon>:31:38: 31:43 error: use of possibly uninitialized variable: `cache` [E0381]
<anon>:31 p = Parent { cache: RefCell::new(cache) };