I'm having a lot of fun trying to solve the robot simulator Exercism exercise, but I'm facing a value moving problem for which I don't seem to be able to come up with an elegant solution:
impl Robot {
pub fn new(x: isize, y: isize, d: Direction) -> Self {
Robot { position: Coordinate { x: x, y: y }, direction: d }
}
pub fn turn_right(mut self) -> Self {
match self.direction {
// ...
};
self
}
pub fn turn_left(mut self) -> Self {
match self.direction {
// ...
};
self
}
pub fn advance(mut self) -> Self {
match self.direction {
// ...
};
self
}
pub fn instructions(self, instructions: &str) -> Self {
for instruction in instructions.chars() {
match instruction {
'A' => { self.advance(); },
'R' => { self.turn_right(); },
'L' => { self.turn_left(); },
_ => {
println!("{} is not a valid instruction", instruction);
},
};
}
self
}
I get this error :
enter code hereerror[E0382]: use of moved value: `self`
--> src/lib.rs:60:26
|
60 | 'A' => { self.advance(); },
| ^^^^ value moved here in previous iteration of loop
|
= note: move occurs because `self` has type `Robot`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `self`
--> src/lib.rs:61:26
|
60 | 'A' => { self.advance(); },
| ---- value moved here
61 | 'R' => { self.turn_right(); },
| ^^^^ value used here after move
|
= note: move occurs because `self` has type `Robot`, which does not implement the `Copy` trait
I think I get the error because advance() returns self, but I don't understand why the value is still moved as it's used inside a block. Do I really have to implement Copy or am I missing a lifetime use case?
I think I get the error because advance() returns self ?
No, you're getting that error because advance consumes self (and your other methods do, too).
The idiomatic solution to your problem is almost certainly to have your methods take a mutable reference (&mut) to self instead of taking self by value. E.g. the signature pub fn turn_right(mut self) -> Self would become pub fn turn_right(&mut self) (note that the latter does not return anything). You can manipulate the robot's state through the reference, and your instructions function should work fine.
If for some reason you want to continue to have the methods take self by value, you could rewrite instructions as follows:
pub fn instructions(self, instructions: &str) -> Self {
let mut robot = self;
for instruction in instructions.chars() {
robot = match instruction {
'A' => { robot.advance() },
'R' => { robot.turn_right() },
'L' => { robot.turn_left() },
_ => {
println!("{} is not a valid instruction", instruction);
robot
},
};
}
robot
}
I.e. continue passing the robot's state by value, but make sure that the new state is bound to a variable at every loop iteration.
(I've not tried to compile this code, but the principle should be sound.)
Looking at the other users answers, you can actually do it with fold :
pub fn instructions(self, instructions: &str) -> Self {
instructions.chars().fold(self, |robot, c| {
match c {
'L' => robot.turn_left(),
'R' => robot.turn_right(),
'A' => robot.advance(),
_ => panic!("unexpected char")
}
})
}
It seems to keep moving back robot into the scope.
Related
I've implemented a binary tree in Rust as a learning project but failed to transverse it to print the tree in a breadth-first search fashion.
The issue is that I can't reassign the search queue (children) because it's borrowed and doesn't live long enough.
https://gist.github.com/varshard/3874803cd035e27facb67c59e89c3c1c#file-binary_tree-rs-L39
How can I correct this?
use std::fmt::Display;
type Branch<'a, T> = Option<Box<Node<'a, T>>>;
struct Node<'a, T: PartialOrd + Display> {
value: &'a T,
left: Branch<'a, T>,
right: Branch<'a, T>
}
impl<'a, T: PartialOrd + Display> Node<'a, T> {
fn insert(&mut self, value: &'a T) {
let target_node = if value > self.value { &mut self.right } else { &mut self.left };
match target_node {
Some(ref mut node) => node.insert(value),
None => {
let new_node = Node{ value: value, left: None, right: None};
*target_node = Some(Box::new(new_node))
}
}
}
fn display(&'a self) {
let mut children: Vec<Option<&Node<'a, T>>> = Vec::new();
children.push(Some(self));
while children.len() > 0 {
for child in &children {
match child {
Some(node) => {
print!("{} ", node.value);
},
None => {
print!(" ")
}
}
}
println!("");
// Error: children doesn't live long enough;
children = self.to_vec(&children);
}
}
fn to_vec(&self, nodes: &'a Vec<Option<&Node<'a, T>>>) -> Vec<Option<&Node<'a, T>>> {
let mut children: Vec<Option<&Node<'a, T>>> = Vec::new();
for node_option in nodes {
match node_option {
Some(node) => {
match &node.left {
Some(left) => {
children.push(Some(left));
match &node.right {
Some(right) => {
children.push(Some(right));
},
None => {
children.push(None);
}
}
},
None => {
children.push(None);
match &node.right {
Some(right) => {
children.push(Some(right));
},
None => {
children.push(None);
}
}
}
}
},
None => {}
}
}
children
}
}
fn main() {
let root_val = 5;
let mut root = Node{ value: &root_val, left: None, right: None };
root.insert(&3);
root.insert(&4);
root.insert(&1);
root.insert(&6);
root.display();
}
Copying my answer from this reddit comment:
There's a way to directly fix your problem, but I think there are better options for making the code easier to write and understand. For the direct fix, you can make some lifetime adjustments. Instead of
fn to_vec(&self, nodes: &'a Vec<Option<&Node<'a, T>>>) -> Vec<Option<&Node<'a, T>>> {
You need:
fn to_vec<'b>(&self, nodes: &Vec<Option<&'b Node<'a, T>>>) -> Vec<Option<&'b Node<'a, T>>>
What's the difference there? In the first case we're saying that nodes is a &'a Vec. That is, a borrow of a Vec that lives as long as the value references inside your tree. That's a long time to live, and it's what the compiler's getting angry about.
Now, if you just take the 'a off of that &Vec, the compiler complains about something else:
|
42 | fn to_vec(&self, nodes: &Vec<Option<&Node<'a, T>>>) -> Vec<Option<&Node<'a, T>>> {
| ------------ -------------------------
| |
| this parameter and the return type are declared with different lifetimes...
...
76 | children
| ^^^^^^^^ ...but data from `nodes` is returned here
Maybe this is the error that pushed you to put the 'a on the &Vec in the first place. We need to solve it a different way. The important thing to understand here is that the return value doesn't contain references directly into the nodes vector, but it does contain copies of the nodes vector's contents, the &Node references. We need to tell the compiler that even though the nodes reference doesn't live very long, its contents do live longer. That's why we create the new lifetime 'b in my fix above.
This is objectively very confusing. Personally, I prefer to avoid solving these tricky problems, by just keeping things alive longer instead of reasoning about exactly how long they live. The source of the difficulty is that we're destroying the children vector on line 39. If we were able to keep it around, and just keep emptying it and refilling it, Rust would give us a much easier time. Have you considered using a std::collections::VecDeque instead of a Vec here? You could construct it once outside of your while-loop, and then you could pass &mut children around, without worrying very much about its lifetime. I think a queue is usually the go-to data structure for a breadth-first traversal, with new children added to the back, and the traversal itself reading from the front.
I have a Vec of optional HashSets. If the slot is None, I want to allocate a HashSet and store it in the Vec.
In both cases, I want to add to the HashSet.
I understand what the compiler error is complaining about but not what syntax will make the problem go away. The compiler's suggested change also does not compile, as well as any other syntax I try. How do I match the Vec cell, check if it is None, allocate a Some<HashSet> if it is None or just access the HashSet if it does exist and in both cases add in a new integer to the set?
THE CODE:
use std::collections::HashSet;
use std::collections::BTreeSet;
use std::iter::FromIterator;
use maplit;
pub struct Graph {
outgoing_edges : Vec<Option<HashSet<usize>>>,
incoming_edges : Vec<Option<HashSet<usize>>>
}
impl Graph {
pub fn new(node_count : usize) -> Self {
Graph {
outgoing_edges : vec!(None; node_count),
incoming_edges : vec!(None; node_count)
}
}
/// Add a directional edge that starts at `from_node` and points to `to_node`.
pub fn add_edge(&mut self, from_node : usize, to_node : usize) {
match &self.outgoing_edges[from_node] {
Some(mut set) => { set.insert(to_node); () },
None => { self.outgoing_edges[from_node] = Some(hashset!{ to_node }); () }
}
match &self.incoming_edges[to_node] {
Some(mut set) => { set.insert(from_node); () },
None => { self.incoming_edges[to_node] = Some(hashset!{ from_node }); () }
}
}
}
THE ERROR:
(Line numbers are from my original file, not the short code snippet. The error message is from before I added the ampersand to borrow, as shown above, but that code change didn't work.)
error[E0507]: cannot move out of index of `std::vec::Vec<std::option::Option<std::collections::HashSet<usize>>>`
--> src\graph\mod.rs:46:15
|
46 | match self.outgoing_edges[from_node] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider borrowing here: `&self.outgoing_edges[from_node]`
47 | Some(mut set) => { set.insert(to_node); () },
| -------
| |
| data moved here
| move occurs because `set` has type `std::collections::HashSet<usize>`, which does not implement the `Copy` trait
Instead of using pattern matching, you can use the method Option::get_or_insert_with() to create a new hash set if required, and return a reference to either the existing or the newly created hash set. The full code could look like this:
pub fn add_edge(&mut self, from_node: usize, to_node: usize) {
self.outgoing_edges[from_node]
.get_or_insert_with(HashSet::new)
.insert(to_node);
self.incoming_edges[to_node]
.get_or_insert_with(HashSet::new)
.insert(from_node);
}
This is pretty straightforward, you want to bind by reference:
/// Add a directional edge that starts at `from_node` and points to `to_node`.
pub fn add_edge(&mut self, from_node : usize, to_node : usize) {
match self.outgoing_edges[from_node] {
Some(ref mut set) => { set.insert(to_node); },
None => { self.outgoing_edges[from_node] = Some(hashset!{ to_node }); }
}
match self.incoming_edges[to_node] {
Some(ref mut set) => { set.insert(from_node); },
None => { self.incoming_edges[to_node] = Some(hashset!{ from_node }); }
}
}
Or with pattern matching ergonomics feature called binding mode, you can also do the following:
/// Add a directional edge that starts at `from_node` and points to `to_node`.
pub fn add_edge(&mut self, from_node : usize, to_node : usize) {
match &mut self.outgoing_edges[from_node] {
Some(set) => { set.insert(to_node); },
None => { self.outgoing_edges[from_node] = Some(hashset!{ to_node }); }
}
match &mut self.incoming_edges[to_node] {
Some(set) => { set.insert(from_node); },
None => { self.incoming_edges[to_node] = Some(hashset!{ from_node }); }
}
}
This question already has answers here:
Is there any way to return a reference to a variable created in a function?
(5 answers)
Closed 3 years ago.
I am trying to create a lexical analyzer which uses itertools::PutBack to make an iterator over the characters in a String. I intend to store the pushback iterator in a struct and delegate methods to it so that I can categorize the characters by an enum, which will then be passed to a state machine at the core of the lexical analyzer (not yet written).
The borrow-checker is not happy with me. Method ParserEventIterator::new near the bottom of the listing causes the error. How do I define the lifetimes or borrowing so that I can get this to compile? Or what Rustic data structure design should I use in its stead?
Ultimately, I would like this to implement the appropriate traits to become a proper iterator. (Newbie to Rust. Prior to this, I have programmed in 28 languages, but this one has me stumped.)
Here is a code sample:
extern crate itertools;
use itertools::put_back;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;
pub enum ParserEvent {
Letter(char),
Digit(char),
Other(char),
}
impl ParserEvent {
fn new(c: char) -> ParserEvent {
match c {
'a'...'z' | 'A'...'Z' => ParserEvent::Letter(c),
'0'...'9' => ParserEvent::Digit(c),
_ => ParserEvent::Other(c),
}
}
}
impl Display for ParserEvent {
fn fmt(&self, f: &mut Formatter) -> Result {
let mut _ctos = |c: char| write!(f, "{}", c.to_string());
match self {
ParserEvent::Letter(letter) => _ctos(*letter),
ParserEvent::Digit(digit) => _ctos(*digit),
ParserEvent::Other(o) => _ctos(*o),
}
}
}
// ParserEventIterator
// Elements ('e) must have lifetime longer than the iterator ('i).
pub struct ParserEventIterator<'i, 'e: 'i> {
char_iter: &'i mut itertools::PutBack<std::str::Chars<'e>>,
}
impl<'i, 'e: 'i> ParserEventIterator<'i, 'e> {
fn new(s: &'e std::string::String) -> ParserEventIterator<'i, 'e> {
// THIS NEXT LINE IS THE LINE WITH THE PROBLEM!!!
ParserEventIterator {
char_iter: &mut put_back(s.chars()),
}
}
fn put_back(&mut self, e: ParserEvent) -> () {
if let Some(c) = e.to_string().chars().next() {
self.char_iter.put_back(c);
}
}
}
impl<'i, 'e: 'i> Iterator for ParserEventIterator<'i, 'e> {
type Item = ParserEvent;
fn next(&mut self) -> Option<ParserEvent> {
match self.char_iter.next() {
Some(c) => Some(ParserEvent::new(c)),
None => None,
}
}
}
fn main() {
let mut _i = ParserEventIterator::new(&String::from("Hello World"));
}
On the Rust Playground
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:43:9
|
43 | / ParserEventIterator {
44 | | char_iter: &mut put_back(s.chars()),
| | ------------------- temporary value created here
45 | | }
| |_________^ returns a value referencing data owned by the current function
Well, the compiler is almost telling you the solution by reflecting to the obvious problem: you can't have a borrow which doesn't live long enough, i.e. the borrow would point to a nonexistent location after the stack memory of the function has been destroyed.
This would happen because the borrow is referencing an object (in this case an itertools::struct::PutBack instance) that has been newly created within the function body. This instance gets destroyed at the end of the function along with all the references to it. So the compiler is preventing you to have a so called dangling pointer.
Thus, instead of borrowing you should move the PutBack instance into your struct:
// ...
pub struct ParserEventIterator<'e> {
char_iter: itertools::PutBack<std::str::Chars<'e>>
}
impl<'e> ParserEventIterator<'e> {
fn new(s: &'e std::string::String) -> ParserEventIterator<'e> {
ParserEventIterator { char_iter: put_back(s.chars()) }
}
// ...
}
I'm running into some problems with lifetime of variables in Rust. The x variable in do_stuff is borrowed to try_wrap and can thus not be returned in the None case. Am I thinking about this the wrong way?
struct NonCopyable;
impl NonCopyable {
fn new() -> Self {
NonCopyable
}
}
fn do_stuff() -> NonCopyable {
let x = NonCopyable::new();
match try_wrap(x) {
Some(val) => val,
None => x,
}
}
fn try_wrap(x: NonCopyable) -> Option<NonCopyable> {
None
}
fn main() {}
error[E0382]: use of moved value: `x`
--> src/main.rs:13:17
|
11 | match try_wrap(x) {
| - value moved here
12 | Some(val) => val,
13 | None => x,
| ^ value used here after move
|
= note: move occurs because `x` has type `NonCopyable`, which does not implement the `Copy` trait
with lifetime of variables
There are no lifetimes involved here
The x variable in do_stuff is borrowed
No, it is not.
Am I thinking about this the wrong way?
Yes. Borrowing is indicated by an ampersand & and/or a lifetime parameter 'foo:
&i32 // a borrowed integer
&'a str // a borrowed string slice with a lifetime
Foo<'b> // a type that contains a borrow of some kind
Your try_wrap function takes ownership of x:
fn try_wrap(x: NonCopyable) -> Option<NonCopyable>
That means x is gone and the calling function cannot access it anymore. It has been moved into try_wrap, which is now free to do whatever it wants with the value, including destroy it. That is why the calling function is no longer able to safely access it and why you get the error.
If the type implemented Copy, the compiler would have instead implicitly created a copy of the value and passed it in. If the type implemented Clone, you could have explicitly called .clone() on the argument to try_wrap in order to keep the local value.
As Florian Weimer notes, you can use a type to return either the wrapped value or the original. It's difficult to tell based on your example, but I disagree with using Result unless it's an error. Instead, I'd create my own one-off enum or use something like Either:
extern crate either;
use either::Either;
fn do_stuff() -> NonCopyable {
let x = NonCopyable::new();
match try_wrap(x) {
Either::Left(val) => val,
Either::Right(x) => x,
}
}
fn try_wrap(x: NonCopyable) -> Either<NonCopyable, NonCopyable> {
Either::Right(x)
}
You could also embed the logic of try_wrap back into do_stuff, or split up try_wrap so that the logic doesn't require ownership:
fn do_stuff() -> NonCopyable {
let x = NonCopyable::new();
if should_wrap(&x) { do_wrap(x) } else { x }
}
fn should_wrap(x: &NonCopyable) -> bool { false }
fn do_wrap(x: NonCopyable) -> NonCopyable { x }
Since you are returning the same type, it's also possible you would want to take a mutable reference to the value and just do whatever conditional changes need to happen:
fn do_stuff() -> NonCopyable {
let mut x = NonCopyable::new();
try_wrap(&mut x);
x
}
fn try_wrap(x: &mut NonCopyable) {}
I think Option<NonCopyable> is simply the wrong return type for try_wrap. You need a two-armed sum type here like Result, so that the caller can recover the argument in case of an error, perhaps like this:
fn do_stuff() -> NonCopyable {
let x = NonCopyable::new();
match try_wrap(x) {
Ok(val) => val,
Err(x) => x,
}
}
fn try_wrap(x: NonCopyable) -> Result<NonCopyable, NonCopyable> {
Err(x)
}
How to get this example to compile without array copying or multiple calls to b() per iteration — b() has to perform some expensive parsing?
This is not the full code that I wrote, but it illustrates the problem I had. Here, Test is attempting to perform some kind of streaming parsing work. c() is the parsing function, it returns Some when parsing was successful. b() is a function that attempts to read more data from the stream when c() can not parse using the available data yet. The returned value is a slice into the self.v containing the parsed range.
struct Test {
v: [u8; 10],
index: u8,
}
impl Test {
fn b(&mut self) {
self.index = 1
}
fn c(i: &[u8]) -> Option<&[u8]> {
Some(i)
}
fn a(&mut self) -> &[u8] {
loop {
self.b();
match Test::c(&self.v) {
Some(r) => return r,
_ => continue,
}
}
}
}
fn main() {
let mut q = Test {
v: [0; 10],
index: 0,
};
q.a();
}
When compiling, it produces the following borrow checker error:
error[E0502]: cannot borrow `*self` as mutable because `self.v` is also
borrowed as immutable
--> <anon>:17:13
|
17 | self.b();
| ^^^^ mutable borrow occurs here
18 |
19 | match Test::c(&self.v) {
| ------ immutable borrow occurs here
...
24 | }
| - immutable borrow ends here
If I change a() to:
fn a(&mut self) -> Option<&[u8]> {
loop {
self.b();
if let None = Test::c(&self.v) {
continue
}
if let Some(r) = Test::c(&self.v) {
return Some(r);
} else {
unreachable!();
}
}
}
Then it runs, but with the obvious drawback of calling the parsing function c() twice.
I kind of understand that changing self while the return value depends on it is unsafe, however, I do not understand why is the immutable borrow for self.v is still alive in the next iteration, when we attempted to call b() again.
Right now "Rustc can't "deal" with conditional borrowing returns". See this comment from Gankro on issue 21906.
It can't assign a correct lifetime to the borrow if only one execution path terminates the loop.
I can suggest this workaround, but I'm not sure it is optimal:
fn c(i: &[u8]) -> Option<(usize, usize)> {
Some((0, i.len()))
}
fn a(&mut self) -> &[u8] {
let parse_result;
loop {
self.b();
match Test::c(&self.v) {
Some(r) => {
parse_result = r;
break;
}
_ => {}
}
}
let (start, end) = parse_result;
&self.v[start..end]
}
You can construct result of parsing using array indexes and convert them into references outside of the loop.
Another option is to resort to unsafe to decouple lifetimes. I am not an expert in safe use of unsafe, so pay attention to comments of others.
fn a(&mut self) -> &[u8] {
loop {
self.b();
match Test::c(&self.v) {
Some(r) => return unsafe{
// should be safe. It decouples lifetime of
// &self.v and lifetime of returned value,
// while lifetime of returned value still
// cannot outlive self
::std::slice::from_raw_parts(r.as_ptr(), r.len())
},
_ => continue,
}
}
}