I'm trying to implement a simple REPL calculator in Rust and I'm hitting brick walls all over the place.
I'm consuming chars while iterating over a hardcoded string. When I hit a numeric character I want to pass control over to a function that will consume the rest of the number (assuming the number has more than one digit) and return the number, converted to an Integer.
I'm having trouble with passing Chars iterator to a function. The error I'm getting is use of moved value: 'iter'.
I understand that I can't mutate something that I gave to someone else - something that had its ownership moved - but I don't know any other way of doing this, especially since the Chars iterator is non-copyable.
#[derive(Clone, Debug)]
enum Token {
Addition,
Substraction,
Multiplication,
Division,
Integer(i32),
Error,
}
fn consume_number(mut iter: std::str::Chars) -> Option<i32> {
while let Some(item) = iter.next() {
println!("{:?}", item);
}
return Some(1337);
}
fn tokenize(line: &str) -> Vec<Token> {
let mut iter = line.chars();
let mut tokens = Vec::new();
let mut token;
while let Some(c) = iter.next() {
if c.is_whitespace() { continue };
if c.is_digit(10) {
token = match consume_number(iter) {
Some(i32) => Token::Integer(i32),
None => Token::Error,
};
} else {
token = match c {
'+' => Token::Addition,
'-' => Token::Substraction,
'*' => Token::Multiplication,
'/' => Token::Division,
_ => Token::Error,
};
};
tokens.push(token);
}
return tokens;
}
fn main() {
let line = "631 * 32 + 212 - 15 / 89";
println!("{:?}", tokenize(&line));
}
The answer is yes, it's done in the FromIterator trait.
What you experience here is much more basic:
fn consume_number(mut iter: std::str::Chars) -> Option<i32> { ... }
while let Some(c) = iter.next() {
...
match_consume_number(iter)
...
}
When calling match_consume_number you are transferring ownership of the iterator to it. It means that at the next iteration of the loop body, this iter variable is no longer available.
If the iterator is meant to still be usable afterward, you should pass a reference to it:
fn consume_number(iter: &mut std::str::Chars) -> Option<i32> { ... }
while let Some(c) = iter.next() {
...
match_consume_number(&mut iter)
...
}
You were close!
Related
I modified the code from the Rust Book's Guessing Game Tutorial to make it a little shorter; for a slide. Alas, I've introduced a bug, and it no longer executes correctly: the first input works as expected, but subsequent entries now yield no feedback.
What is the best way to guard against this situation?
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
let mut guess = String::new();
loop {
io::stdin().read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
read_line will append the line to buffer, so your guess will accumulate all the inputs include newline characters! Moving let mut guess = String::new(); inside the loop solves the problem:
fn main() {
...
loop {
let mut guess = String::new();
...
}
}
Is it possible to loop over a Vec, calling a method that returns a Future on each, and build a chain of Futures, to be evaluated (eventually) by the consumer? Whether to execute the later Futures would depend on the outcome of the earlier Futures in the Vec.
To clarify:
I'm working on an application that can fetch data from an arbitrary set of upstream sources.
Requesting data would check with each of the sources, in turn. If the first source had an error (Err), or did not have the data available (None), then the second source would be tried, and so on.
Each source should be tried exactly once, and no source should be tried until all of the sources before have returned their results. Errors are logged, but otherwise ignored, passing the query to the next upstream data source.
I have some working code that does this for fetching metadata:
/// Attempts to read/write data to various external sources. These are
/// nested types, because a data source may exist as both a reader and a writer
struct StoreManager {
/// Upstream data sources
readers: Vec<Rc<RefCell<StoreRead>>>,
/// Downstream data sinks
writers: Vec<Rc<RefCell<StoreWrite>>>,
}
impl StoreRead for StoreManager {
fn metadata(self: &Self, id: &Identifier) -> Box<Future<Option<Metadata>, Error>> {
Box::new(ok(self.readers
.iter()
.map(|store| {
executor::block_on(store.borrow().metadata(id)).unwrap_or_else(|err| {
error!("Error on metadata(): {:?}", err);
None
})
})
.find(Option::is_some)
.unwrap_or(None)))
}
}
Aside from my unhappiness with all of the Box and Rc/RefCell nonsense, my real concern is with the executor::block_on() call. It blocks, waiting for each Future to return a result, before continuing to the next.
Given that it's possible to call fn_returning_future().or_else(|_| other_fn()) and so on, is it possible to build up a dynamic chain like this? Or is it a requirement to fully evaluate each Future in the iterator before moving to the next?
You can use stream::unfold to convert a single value into a stream. In this case, we can use the IntoIter iterator as that single value.
use futures::{executor, stream, Stream, TryStreamExt}; // 0.3.4
type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
async fn network_request(val: i32) -> Result<i32> {
// Just for demonstration, don't do this in a real program
use std::{
thread,
time::{Duration, Instant},
};
thread::sleep(Duration::from_secs(1));
println!("Resolving {} at {:?}", val, Instant::now());
Ok(val * 100)
}
fn requests_in_sequence(vals: Vec<i32>) -> impl Stream<Item = Result<i32>> {
stream::unfold(vals.into_iter(), |mut vals| async {
let val = vals.next()?;
let response = network_request(val).await;
Some((response, vals))
})
}
fn main() {
let s = requests_in_sequence(vec![1, 2, 3]);
executor::block_on(async {
s.try_for_each(|v| async move {
println!("-> {}", v);
Ok(())
})
.await
.expect("An error occurred");
});
}
Resolving 1 at Instant { tv_sec: 6223328, tv_nsec: 294631597 }
-> 100
Resolving 2 at Instant { tv_sec: 6223329, tv_nsec: 310839993 }
-> 200
Resolving 3 at Instant { tv_sec: 6223330, tv_nsec: 311005834 }
-> 300
To ignore Err and None, you have to shuttle the Error over to the Item, making the Item type a Result<Option<T>, Error>:
use futures::{executor, stream, Stream, StreamExt}; // 0.3.4
type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
async fn network_request(val: i32) -> Result<Option<i32>> {
// Just for demonstration, don't do this in a real program
use std::{
thread,
time::{Duration, Instant},
};
thread::sleep(Duration::from_secs(1));
println!("Resolving {} at {:?}", val, Instant::now());
match val {
1 => Err("boom".into()), // An error
2 => Ok(None), // No data
_ => Ok(Some(val * 100)), // Success
}
}
fn requests_in_sequence(vals: Vec<i32>) -> impl Stream<Item = Result<Option<i32>>> {
stream::unfold(vals.into_iter(), |mut vals| async {
let val = vals.next()?;
let response = network_request(val).await;
Some((response, vals))
})
}
fn main() {
executor::block_on(async {
let s = requests_in_sequence(vec![1, 2, 3]);
let s = s.filter_map(|v| async move { v.ok() });
let s = s.filter_map(|v| async move { v });
let mut s = s.boxed_local();
match s.next().await {
Some(v) => println!("First success: {}", v),
None => println!("No successful requests"),
}
});
}
Resolving 1 at Instant { tv_sec: 6224229, tv_nsec: 727216392 }
Resolving 2 at Instant { tv_sec: 6224230, tv_nsec: 727404752 }
Resolving 3 at Instant { tv_sec: 6224231, tv_nsec: 727593740 }
First success: 300
is it possible to build up a dynamic chain like this
Yes, by leveraging async functions:
use futures::executor; // 0.3.4
type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
async fn network_request(val: i32) -> Result<Option<i32>> {
// Just for demonstration, don't do this in a real program
use std::{
thread,
time::{Duration, Instant},
};
thread::sleep(Duration::from_secs(1));
println!("Resolving {} at {:?}", val, Instant::now());
match val {
1 => Err("boom".into()), // An error
2 => Ok(None), // No data
_ => Ok(Some(val * 100)), // Success
}
}
async fn requests_in_sequence(vals: Vec<i32>) -> Result<i32> {
let mut vals = vals.into_iter().peekable();
while let Some(v) = vals.next() {
match network_request(v).await {
Ok(Some(v)) => return Ok(v),
Err(e) if vals.peek().is_none() => return Err(e),
Ok(None) | Err(_) => { /* Do nothing and try the next source */ }
}
}
Err("Ran out of sources".into())
}
fn main() {
executor::block_on(async {
match requests_in_sequence(vec![1, 2, 3]).await {
Ok(v) => println!("First success: {}", v),
Err(e) => println!("No successful requests: {}", e),
}
});
}
See also:
Creating Diesel.rs queries with a dynamic number of .and()'s
is it a requirement to fully evaluate each Future in the iterator before moving to the next
Isn't that part of your own requirements? Emphasis mine:
Requesting data would check with each of the sources, in turn. If the first source had an error (Err), or did not have the data available (None), then the second source would be tried
I am reading a file and parsing the data:
fn main() {
parse_torrentfile("ubuntu-16.04.1-server-amd64.torrent");
}
fn parse_file(filename: &'static str) {
let mut f = File::open(&Path::new(filename)).unwrap();
let mut v: Vec<u8> = Vec::new();
let file_content = f.read_to_end(&mut v);
println!("{:?}", file_content);
}
If ubuntu-16.04.1-server-amd64.torrent is present, this works well, but if it isn't present, this error occurs:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 2, message: "No such file or directory" } }'
How can I print "Not Exist File" or "process file parsing"?
You should be matching on the Result instead of calling unwrap() or expect(). Once you've got the error, you can either print it out or look at the ErrorKind if you want to handle different errors differently.
use std::fs::File;
use std::path::Path;
use std::io::Read;
fn main() {
parse_file("doesnt_exist.txt");
}
fn parse_file(filename: &'static str) {
let mut f = match File::open(&Path::new(filename)) {
Ok(f) => f,
Err(e) => {
use std::io::ErrorKind::*;
println!("Got error: {}", e);
match e.kind() {
NotFound => {
println!("File not found");
}
k => {
println!("Error: {:?}", k);
}
}
return;
}
};
let mut v: Vec<u8> = Vec::new();
let file_content = f.read_to_end(&mut v);
println!("{:?}", file_content);
}
Playground
Probably the most idiomatic approach would be propagating the result outside parse_file, printing the error in main.
use std::fs::File;
use std::io::{Read, Error as IoError};
use std::path::Path;
fn main() {
match parse_file("ubuntu-16.04.1-server-amd64.torrent") {
Err(e) => println!("{}", e),
_ => {}
}
}
fn parse_file(filename: &'static str) -> Result<(), IoError> {
let mut f = File::open(&Path::new(filename))?;
let mut v: Vec<u8> = Vec::new();
let file_content = f.read_to_end(&mut v);
println!("{:?}", file_content);
Ok(())
}
If you want to print the error in one line and then propagating it, you could do something like this instead:
fn main() {
parse_file("ubuntu-16.04.1-server-amd64.torrent");
}
fn parse_file(filename: &'static str) -> Result<(), IoError> {
let mut f = File::open(&Path::new(filename)).map_err(|e| {
println!("{}", e);
e
})?;
let mut v: Vec<u8> = Vec::new();
let file_content = f.read_to_end(&mut v);
println!("{:?}", file_content);
Ok(())
}
I'd like to write a prompt function that sends a passed-in string to stdout and then returns the string that it reads from stdin. How could I test it?
Here is an example of the function:
fn prompt(question: String) -> String {
let mut stdin = BufferedReader::new(stdin());
print!("{}", question);
match stdin.read_line() {
Ok(line) => line,
Err(e) => panic!(e),
}
}
And here is my testing attempt
#[test]
fn try_to_test_stdout() {
let writer: Vec<u8> = vec![];
set_stdout(Box::new(writer));
print!("testing");
// `writer` is now gone, can't check to see if "testing" was sent
}
Use dependency injection. Coupling it with generics and monomorphism, you don't lose any performance:
use std::io::{self, BufRead, Write};
fn prompt<R, W>(mut reader: R, mut writer: W, question: &str) -> String
where
R: BufRead,
W: Write,
{
write!(&mut writer, "{}", question).expect("Unable to write");
let mut s = String::new();
reader.read_line(&mut s).expect("Unable to read");
s
}
#[test]
fn test_with_in_memory() {
let input = b"I'm George";
let mut output = Vec::new();
let answer = prompt(&input[..], &mut output, "Who goes there?");
let output = String::from_utf8(output).expect("Not UTF-8");
assert_eq!("Who goes there?", output);
assert_eq!("I'm George", answer);
}
fn main() {
let stdio = io::stdin();
let input = stdio.lock();
let output = io::stdout();
let answer = prompt(input, output, "Who goes there?");
println!("was: {}", answer);
}
In many cases, you'd want to actually propagate the error back up to the caller instead of using expect, as IO is a very common place for failures to occur.
This can be extended beyond functions into methods:
use std::io::{self, BufRead, Write};
struct Quizzer<R, W> {
reader: R,
writer: W,
}
impl<R, W> Quizzer<R, W>
where
R: BufRead,
W: Write,
{
fn prompt(&mut self, question: &str) -> String {
write!(&mut self.writer, "{}", question).expect("Unable to write");
let mut s = String::new();
self.reader.read_line(&mut s).expect("Unable to read");
s
}
}
#[test]
fn test_with_in_memory() {
let input = b"I'm George";
let mut output = Vec::new();
let answer = {
let mut quizzer = Quizzer {
reader: &input[..],
writer: &mut output,
};
quizzer.prompt("Who goes there?")
};
let output = String::from_utf8(output).expect("Not UTF-8");
assert_eq!("Who goes there?", output);
assert_eq!("I'm George", answer);
}
fn main() {
let stdio = io::stdin();
let input = stdio.lock();
let output = io::stdout();
let mut quizzer = Quizzer {
reader: input,
writer: output,
};
let answer = quizzer.prompt("Who goes there?");
println!("was: {}", answer);
}
I'm iterating through an array, and depending on the current value, I'd like to pass the iterator to a sub function and have it deal with a number of values, and upon exiting the sub function, carry on iterating through the array. Below is the closest I've managed to get so far, but I keep getting error: use of moved value: 'iter'.
I've tried looking into lifetimes, but that hasn't worked for me either. I've spent most of a day on this now, and can't seem to get anywhere with it. Any help would be greatly appreciated. Thanks.
enum Thing {
Three(char, char, char),
Four(char, char, char, char),
}
fn take_three <'a>(iter: &mut std::slice::Iter<'a, char>) -> Thing {
let a = iter.next().unwrap();
let b = iter.next().unwrap();
let c = iter.next().unwrap();
Thing::Three(*a,*b,*c)
}
fn take_four <'a>(iter: &mut std::slice::Iter<'a, char>) -> Thing {
let a = iter.next().unwrap();
let b = iter.next().unwrap();
let c = iter.next().unwrap();
let d = iter.next().unwrap();
Thing::Four(*a,*b,*c,*d)
}
fn parse_tokens (tokens: &Vec<char>) {
let mut iter = tokens.iter();
let mut things: Vec<Thing> = vec![];
for token in iter {
match token {
&'a' => things.push(take_three(&mut iter)),
&'b' => things.push(take_four(&mut iter)),
_ => {},
}
}
}
fn main() {
let tokens = vec!['a', '1', '2', '3', 'b', '1', '2', '3', '4', 'a', '4', '5', '6'];
parse_tokens(&tokens);
}
The for construct consumes the iterator, and doing what you want using it will be quite tricky (if not impossible, I'm really not sure about that).
However, you can have it working pretty easily by switching to a while let construct, like this:
fn parse_tokens (tokens: &Vec<char>) {
let mut iter = tokens.iter();
let mut things: Vec<Thing> = vec![];
while let Some(token) = iter.next() {
match token {
&'a' => things.push(take_three(&mut iter)),
&'b' => things.push(take_four(&mut iter)),
_ => {},
}
}
}