Suppose I expect a line with 3 integers from stdin. What's the easiest way to read and parse them? What's the Rust equivalent of a, b, c = map(int, input().split())
in Python or scanf("%d %d %d", &a, &b, &c);
in C?
The best way I came up with was something like:
let mut line = String::new();
io::stdin().read_line(&mut line).unwrap();
let parts: Vec<&str> = line.split_whitespace().collect();
let a: i32 = parts[0].parse().unwrap();
let b: i32 = parts[1].parse().unwrap();
let c: i32 = parts[2].parse().unwrap();
Is there a simpler way?
You can use text_io
for this:
#[macro_use] extern crate text_io;
fn main() {
// reads until a whitespace is encountered
let a: i32 = read!();
let b: i32 = read!();
let c: i32 = read!();
}
text_io
0.1.3
also supports a scan!
macro:
let (a, b, c): (i32, i32, i32);
scan!("{}, {}, {}\n", a, b, c);
in case you want to read from a file or some other source, you can also use both macros on any type that implements Iterator<Item=u8>
:
use std::io::Read;
let mut file = std::fs::File::open("text.txt").unwrap()
.bytes()
.map(Result::unwrap);
let x: i32 = read!("{}\n", file);
or
let (x, y, z): (i32, i32, i32);
scan!(file => "{}, {}: {}", x, y, z);
You can leave off the : i32
s if the compiler can infer those types from context.
Disclaimer: I am the author of text_io
.
You can use scan-rules
for this:
/*!
Add this to your `Cargo.toml`, or just run with `cargo script`:
```cargo
[dependencies]
scan-rules = "0.1.1"
```
*/
#[macro_use] extern crate scan_rules;
fn main() {
print!("Enter 3 ints: ");
readln! {
(let a: i32, let b: i32, let c: i32) => {
println!("a, b, c: {}, {}, {}", a, b, c);
}
}
}
If you want to do something a little more involved, you can use multiple rules and type inference, and specify what to do if the input doesn't match any of the rules given (by default it panic!
s):
readln! {
// Space-separated ints
(let a: i32, let b: i32, let c: i32) => {
println!("a b c: {} {} {}", a, b, c);
},
// Comma-separated ints, using inference.
(let a, ",", let b, ",", let c) => {
let a: i32 = a;
let b: i32 = b;
let c: i32 = c;
println!("a, b, c: {}, {}, {}", a, b, c);
},
// Comma-separated list of *between* 1 and 3 integers.
([let ns: i32],{1,3}) => {
println!("ns: {:?}", ns);
},
// Fallback if none of the above match.
(..line) => {
println!("Invalid input: {:?}", line);
}
}
Disclaimer: I am the author of scan-rules
.
I am new to Rust so I may not have all this down exactly but I have made a solution. I discovered you can use split_white_space to put the integers in the string into an iterator. Then you unwrap it out of std::option::Option<&str> using ".unwrap()". After parse the &str using ".parse()" and unwrap its result using ".unwrap()". Then you have an int if you have specified the type of variable using "variable_name: i32 =...". Checkout what I did:
let mut numbers = String::new();
io::stdin()
.read_line(&mut numbers)
.ok()
.expect("read error");
let mut iter = numbers.split_whitespace();
let mut x: i32 = iter.next().unwrap().parse().unwrap();
let mut y: i32 = iter.next().unwrap().parse().unwrap();
let mut n: i32 = iter.next().unwrap().parse().unwrap();
println!("{},{},{}", x, y, n);