(new to rust) I am making a simple program that prints out the numbers between 0 and a number from a terminal argument and i want to turn that number from a string to a i128. What is the neccesary steps to achieve this?
My current code:
use std::env;
fn main()
{
let args: String = env::args().skip(1).collect::<Vec<String>>().join(" ");
println!("{}", 0..args.parse::<i128>().unwrap());
}
expecting: (Input: 10)
0
1
2
3
4
5
6
7
8
9
10
got:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: Empty }', src/main.rs:11:40
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
To get input from the console, use use std::io;. Also you can't print a range using println!() macro, you have to use a for loop to do it.
Note: read_line() doesn't trim the newline character from the input, hence you need to remove the newline character before parsing the input string.
Here is a program to accept input from user and print the range from 0 till user input:
use std::io;
fn main() -> io::Result<()>
{
let mut user_input = String::new();
println!("Enter a number: ");
let stdin = io::stdin();
stdin.read_line(&mut user_input)?;
let num: i128 = user_input.trim_end().parse().unwrap();
for x in 0..=num {
println!("{}", x);
}
Ok(())
}
Related
How can I read from the console and avoid crashing if the user presses enter without entering anything?
let mut objectnumber = String::new();
println!("mennyi súlyt szeretnél megnézni? 3.=255 int");
if io::stdin().read_line(&mut objectnumber).is_ok() {
println!("{}csdcds", objectnumber);
}
//panic!("{}",objectnumber.len());
if objectnumber.len() < 3 {
let localrandnum: u8 = thread_rng().gen_range(0..=255);
println!("miután nem adtál meg semmit sem ezért {localrandnum}.at írtam be neked");
objectnumber = localrandnum.to_string();
}
let objectnumber: u8 = objectnumber.trim().parse::<u8>().expect("null");
This is working but I don't think it should be done like this in Rust.
I don't know why is it ok even on empty line while the parse is talking about it being empty.
Fixes I made:
read_line returns a Result indicating whether or not there was an error reading from stdin. Usually this only happens in very specific circumstances, so let's just unwrap this for now.
objectnumber.len() gives you the length of the string, not its content. To check its content for < 3, we need to parse() it to a u8 first.
Don't expect the parse, because this one depends on user input. Do a proper error handling instead. This is the point that will tell you if the number is >255, <0 or something else entirely. Let's for now just default to '0', because it will then get caught by the < 3.
Don't convert the number you generated with the thread_rng to a String; instead, write it to objectnumber directly. There is no point in converting it to a String and back.
use std::io;
use rand::{thread_rng, Rng};
fn main() {
let mut objectnumber = String::new();
println!("mennyi súlyt szeretnél megnézni? 3.=255 int");
io::stdin()
.read_line(&mut objectnumber)
.expect("Unable to read from stdin!");
// Convert from String to u8
let mut objectnumber: u8 = objectnumber.trim().parse::<u8>().unwrap_or(0);
if objectnumber < 3 {
objectnumber = thread_rng().gen_range(0..=255);
println!("miután nem adtál meg semmit sem ezért {objectnumber}.at írtam be neked");
}
println!("objectnumber: {}", objectnumber);
}
mennyi súlyt szeretnél megnézni? 3.=255 int
33
objectnumber: 33
mennyi súlyt szeretnél megnézni? 3.=255 int
1
miután nem adtál meg semmit sem ezért 191.at írtam be neked
objectnumber: 191
I am writing a paper about how python and Rust differ when used on coding challenges. I have to preface this with the fact that this is my first Rust program ever. So sorry if I'm doing some weird stuff. However, when I am looping through some input in Rust, I get this error:
2
4
1
2
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }', src\main.rs:24:14
Here is my code:
use std::fs::File;
use std::io::{Read};
use std::cmp;
fn main() {
let mut file = File::open("C:\\Users\\isaak\\OneDrive\\skewl\\Fall 2019\\Operating Systems\\rustyboi\\src\\bus.txt").expect("Can't Open File");
let mut contents = String::new();
file.read_to_string(&mut contents).expect("Can't Read File");
let tokens:Vec<&str> = contents.split("\n").collect();
let l1:Vec<&str> = tokens[0].split(" ").collect();
let _n = l1[0];
let w = l1[1];
//println!("{}", w);
let l2 = tokens[1].split(" ");
let mut k = 0;
let mut maxed = 0;
let mut mined = 0;
for item in l2 { // in range n
println!("{}", item);
k += item.parse::<i32>().unwrap();
maxed = cmp::max(k, maxed);
mined = cmp::min(k, mined);
}
println!("{}", cmp::max(w.parse::<i32>().unwrap() - maxed + mined.abs() + 1, 0));
}
The file that it is looking at only contains this:
4 10
2 4 1 2
I am not sure how I could be getting that error on the k+= part in the for loop when the printed value is definitely a number. Anyway, here is a link to the coding challenge in case you are curious: https://codeforces.com/contest/978/problem/E
The working solution in Rust Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ed17ea24cfcf4b45549846a5c9f1edfd
Your file contains \r\n ends of line ("4 10\r\n2 4 1 2\r\n"), and after splitting by only \n there is \r at the end of each line, therefore parsing fails (\r cannot be parsed into integer).
Use lines() instead of split("\n") as a cross-platform solution.
You may use split_whitespace() instead of split(" ").
I'm writing on STDIN a string of numbers (e.g 4 10 30 232312) and I want to read that and convert to an array (or a vector) of integers, but I can't find the right way. So far I have:
use std::io;
fn main() {
let mut reader = io::stdin();
let numbers = reader.read_line().unwrap();
}
You can do something like this:
use std::io::{self, BufRead}; // (a)
fn main() {
let reader = io::stdin();
let numbers: Vec<i32> =
reader.lock() // (0)
.lines().next().unwrap().unwrap() // (1)
.split(' ').map(|s| s.trim()) // (2)
.filter(|s| !s.is_empty()) // (3)
.map(|s| s.parse().unwrap()) // (4)
.collect(); // (5)
println!("{:?}", numbers);
}
First, we take a lock of the stdin which lets you work with stdin as a buffered reader. By default, stdin in Rust is unbuffered; you need to call the lock() method to obtain a buffered version of it, but this buffered version is the only one for all threads in your program, hence the access to it should be synchronized.
Next, we read the next line (1); I'm using the lines() iterator whose next() method returns Option<io::Result<String>>, therefore to obtain just String you need to unwrap() twice.
Then we split it by spaces and trim resulting chunks from extra whitespace (2), remove empty chunks which were left after trimming (3), convert strings to i32s (4) and collect the result to a vector (5).
We also need to import std::io::BufRead trait (a) in order to use the lines() method.
If you know in advance that your input won't contain more than one space between numbers, you can omit step (3) and move the trim() call from (2) to (1):
let numbers: Vec<i32> =
reader.lock()
.lines().next().unwrap().unwrap()
.trim().split(' ')
.map(|s| s.parse().unwrap())
.collect();
Rust also provides a method to split a string into a sequence of whitespace-separated words, called split_whitespace():
let numbers: Vec<i32> =
reader.read_line().unwrap().as_slice()
.split_whitespace()
.map(|s| s.parse().unwrap())
.collect()
split_whitespace() is in fact just a combination of split() and filter(), just like in my original example. It uses a split() function argument which checks for different kinds of whitespace, not only space characters.
On Rust 1.5.x, a working solution is:
fn main() {
let mut numbers = String::new();
io::stdin()
.read_line(&mut numbers)
.ok()
.expect("read error");
let numbers: Vec<i32> = numbers
.split_whitespace()
.map(|s| s.parse().expect("parse error"))
.collect();
for num in numbers {
println!("{}", num);
}
}
Safer version. This one skips failed parses so that failed unwrap doesn't panic.
Use read_line for reading single line.
let mut buf = String::new();
// use read_line for reading single line
std::io::stdin().read_to_string(&mut buf).expect("");
// this one skips failed parses so that failed unwrap doesn't panic
let v: Vec<i32> = buf
.split_whitespace() // split string into words by whitespace
.filter_map(|w| w.parse().ok()) // calling ok() turns Result to Option so that filter_map can discard None values
.collect(); // collect items into Vector. This determined by type annotation.
You can even read Vector of Vectors like this.
let stdin = io::stdin();
let locked = stdin.lock();
let vv: Vec<Vec<i32>> = locked.lines()
.filter_map(
|l| l.ok().map(
|s| s.split_whitespace()
.filter_map(|word| word.parse().ok())
.collect()))
.collect();
Above one works for inputs like
2 424 -42 124
42 242 23 22 241
24 12 3 232 445
then turns them it into
[[2, 424, -42, 124],
[42, 242, 23, 22, 241],
[24, 12, 3, 232, 445]]
filter_map accepts a closure that returns Option<T> and filters out all Nones.
ok() turns Result<R,E> to Option<R> so that errors can be filtered in this case.
Safer version from Dulguun Otgon just skips all the errors.
In case when you want to don't skip errors please consider usage of next one method.
fn parse_to_vec<'a, T, It>(it: It) -> Result<Vec<T>, <T as FromStr>::Err>
where
T: FromStr,
It: Iterator<Item = &'a str>,
{
it.map(|v| v.parse::<T>()).fold(Ok(Vec::new()), |vals, v| {
vals.and_then(|mut vals| {
v.and_then(|v| {
vals.push(v);
Ok(vals)
})
})
})
}
while using it you can follow usual panicking way with expect
let numbers = parse_to_vec::<i32, _>(data_str.trim().split(" "))
.expect("can't parse data");
or more smarter way with converting to Result
let numbers = parse_to_vec::<i32, _>(data_str.trim().split(" "))
.map_err(|e| format!("can't parse data: {:?}", e))?;
I'm writing on STDIN a string of numbers (e.g 4 10 30 232312) and I want to read that and convert to an array (or a vector) of integers, but I can't find the right way. So far I have:
use std::io;
fn main() {
let mut reader = io::stdin();
let numbers = reader.read_line().unwrap();
}
You can do something like this:
use std::io::{self, BufRead}; // (a)
fn main() {
let reader = io::stdin();
let numbers: Vec<i32> =
reader.lock() // (0)
.lines().next().unwrap().unwrap() // (1)
.split(' ').map(|s| s.trim()) // (2)
.filter(|s| !s.is_empty()) // (3)
.map(|s| s.parse().unwrap()) // (4)
.collect(); // (5)
println!("{:?}", numbers);
}
First, we take a lock of the stdin which lets you work with stdin as a buffered reader. By default, stdin in Rust is unbuffered; you need to call the lock() method to obtain a buffered version of it, but this buffered version is the only one for all threads in your program, hence the access to it should be synchronized.
Next, we read the next line (1); I'm using the lines() iterator whose next() method returns Option<io::Result<String>>, therefore to obtain just String you need to unwrap() twice.
Then we split it by spaces and trim resulting chunks from extra whitespace (2), remove empty chunks which were left after trimming (3), convert strings to i32s (4) and collect the result to a vector (5).
We also need to import std::io::BufRead trait (a) in order to use the lines() method.
If you know in advance that your input won't contain more than one space between numbers, you can omit step (3) and move the trim() call from (2) to (1):
let numbers: Vec<i32> =
reader.lock()
.lines().next().unwrap().unwrap()
.trim().split(' ')
.map(|s| s.parse().unwrap())
.collect();
Rust also provides a method to split a string into a sequence of whitespace-separated words, called split_whitespace():
let numbers: Vec<i32> =
reader.read_line().unwrap().as_slice()
.split_whitespace()
.map(|s| s.parse().unwrap())
.collect()
split_whitespace() is in fact just a combination of split() and filter(), just like in my original example. It uses a split() function argument which checks for different kinds of whitespace, not only space characters.
On Rust 1.5.x, a working solution is:
fn main() {
let mut numbers = String::new();
io::stdin()
.read_line(&mut numbers)
.ok()
.expect("read error");
let numbers: Vec<i32> = numbers
.split_whitespace()
.map(|s| s.parse().expect("parse error"))
.collect();
for num in numbers {
println!("{}", num);
}
}
Safer version. This one skips failed parses so that failed unwrap doesn't panic.
Use read_line for reading single line.
let mut buf = String::new();
// use read_line for reading single line
std::io::stdin().read_to_string(&mut buf).expect("");
// this one skips failed parses so that failed unwrap doesn't panic
let v: Vec<i32> = buf
.split_whitespace() // split string into words by whitespace
.filter_map(|w| w.parse().ok()) // calling ok() turns Result to Option so that filter_map can discard None values
.collect(); // collect items into Vector. This determined by type annotation.
You can even read Vector of Vectors like this.
let stdin = io::stdin();
let locked = stdin.lock();
let vv: Vec<Vec<i32>> = locked.lines()
.filter_map(
|l| l.ok().map(
|s| s.split_whitespace()
.filter_map(|word| word.parse().ok())
.collect()))
.collect();
Above one works for inputs like
2 424 -42 124
42 242 23 22 241
24 12 3 232 445
then turns them it into
[[2, 424, -42, 124],
[42, 242, 23, 22, 241],
[24, 12, 3, 232, 445]]
filter_map accepts a closure that returns Option<T> and filters out all Nones.
ok() turns Result<R,E> to Option<R> so that errors can be filtered in this case.
Safer version from Dulguun Otgon just skips all the errors.
In case when you want to don't skip errors please consider usage of next one method.
fn parse_to_vec<'a, T, It>(it: It) -> Result<Vec<T>, <T as FromStr>::Err>
where
T: FromStr,
It: Iterator<Item = &'a str>,
{
it.map(|v| v.parse::<T>()).fold(Ok(Vec::new()), |vals, v| {
vals.and_then(|mut vals| {
v.and_then(|v| {
vals.push(v);
Ok(vals)
})
})
})
}
while using it you can follow usual panicking way with expect
let numbers = parse_to_vec::<i32, _>(data_str.trim().split(" "))
.expect("can't parse data");
or more smarter way with converting to Result
let numbers = parse_to_vec::<i32, _>(data_str.trim().split(" "))
.map_err(|e| format!("can't parse data: {:?}", e))?;
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]);
}
}
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.
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);
}
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();