Reputation: 959
I am going through the too-many-linked-lists tutorial, looking to implement a simple linked list:
use std::mem;
struct Node{
elem: i32,
next : Link,
}
enum Link {
Empty,
More(Box<Node>),
}
pub struct List{
head: Link,
}
impl List{
pub fn pop_node(&mut self) -> Link{
let node = mem::replace(&mut self.head, Link::Empty);
match node {
Link::More(nd) => {self.head= nd.next;}
_ => ()
};
node
}
}
The pop_node
function is to return the node at the head of the list. However it
does not seem to compile complaining that I moved the variable node
while accessing nd
. Is there a way I can pass the bound variable in a pattern match without owning it?
This is the error I see:
error[E0382]: use of partially moved value: `node`
--> src/first.rs:34:9
|
31 | Link::More(nd) => {self.head= nd.next;}
| -- value partially moved here
...
34 | node
| ^^^^ value used here after partial move
|
= note: partial move occurs because value has type `Box<Node>`, which does not implement the `Copy` trait
help: borrow this field in the pattern to avoid moving `node.0`
|
31 | Link::More(ref nd) => {self.head= nd.next;}
| +++
For more information about this error, try `rustc --explain E0382`.
Any idea what I should be doing here? (I tried things like unpacking the node struct but they didn't seem to work.)
Upvotes: 2
Views: 682
Reputation: 169008
Usually when you're performing this kind of operation, you want the actual element (the i32
here), so maybe return Option<i32>
instead -- None
would indicate that the list was empty. Doing this is much simpler than what you're trying to do. Within the match
you can just return nd.elem
.
impl List{
pub fn pop_node(&mut self) -> Option<i32> {
let node = mem::replace(&mut self.head, Link::Empty);
match node {
Link::More(nd) => {
self.head = nd.next;
Some(nd.elem)
}
Link::Empty => None
}
}
}
Note this operation should be called shift_node
(pop_node
would be expected to remove the last node, not the first).
I'd also consider replacing your Link
type with Option<Box<Node>>
. Then you can use utilities already present on Option
. For example, your mem::replace()
call could be replaced with self.head.take()
and then you're just mapping the result. You can keep the Link
name by making it an alias (type Link = Option<Box<Node>>;
).
use std::mem;
struct Node{
elem: i32,
next: Link,
}
type Link = Option<Box<Node>>;
pub struct List {
head: Link,
}
impl List{
pub fn pop_node(&mut self) -> Option<i32> {
self.head.take().map(|nd| {
self.head = nd.next;
nd.elem
})
}
}
Upvotes: 3