Reputation: 35
I'm trying to test out my Rust skills with a simple program that reads multiple integers from a single line of input. It compiles correctly, but unfortunately when it receives the input of 1 2 3
, it panics, saying that the input wasn't a valid integer. Can someone please explain the reason for this, and also provide an explanation as to how I can fix my program?
use std::io;
fn main() {
let mut string = String::new();
io::stdin().read_line(&mut string);
let int_vec: Vec<u32> = string.split(" ")
.map(|x| x.parse::<u32>().expect("Not an integer!"))
.collect();
for i in (0..int_vec.len()).rev() {
print!("{} ", int_vec[i]);
}
}
Upvotes: 2
Views: 826
Reputation: 88576
You ran into the old problem of the terminating line-ending. Let's try putting
println!("{:?}", string);
in the third line of your code. For the input 1 2 3
it will print (on Windows):
"1 2 3\r\n"
So at some point you are trying to parse "3\r\n"
as integer, which obviously fails. One easy way to remove trailing and leading whitespace from a string is to use trim()
. This works:
let int_vec: Vec<_> = string.trim().split(" ")
.map(|x| x.parse::<u32>().expect("Not an integer!"))
.collect();
Upvotes: 5
Reputation: 222108
This is because io::stdin().read_line(&mut String)
also adds a trailing newline character to the string, which causes the last str after splitting with " "
to be "123\n"
, which is not a valid integer. You can use str::trim()
for this:
use std::io;
fn main() {
let mut string = String::new();
io::stdin().read_line(&mut string);
let int_vec: Vec<u32> = string.trim()
.split(" ")
.map(|x| {
x.parse::<u32>()
.expect("Not an integer!")
})
.collect();
for i in (0..int_vec.len()).rev() {
print!("{} ", int_vec[i]);
}
}
With this change, the program works:
$ ./a
1 2 3
3 2 1
Also, you can simplify your for
loop:
for i in int_vec.iter().rev() {
print!("{} ", i);
}
Upvotes: 8
Reputation: 65059
In addition to Dogberts answer... it might be helpful to see how you might be able to debug this sort of issue with an iterator yourself in future.
The Iterator
trait exposes an inspect
function that you can use to inspect each item. Converting your code to use inspect
both before and after each map results in:
let int_vec: Vec<u32> = string.split(" ")
.inspect(|x| println!("About to parse: {:?}", x))
.map(|x| {
x.parse::<u32>()
.expect("Not an integer!")
})
.inspect(|x| println!("Parsed {:?} successfully!", x))
.collect();
Outputs:
1 2 3
About to parse: "1"
Parsed 1 successfully!
About to parse: "2"
Parsed 2 successfully!
About to parse: "3\n"
thread '<main>' panicked at 'Not an integer!...
Notice what its attempting to parse when it gets to the number 3.
Of course, you can inspect string
all by itself. inspect
is handy though for when iterators are involved.
Upvotes: 11