I want to read input in rust like this C++ example:
main() {
int a,b;
cin>>a>>b; //read user input into a and b. Can be separated by a space character or \n
cout<<"a: "<<a<<'\n'<<"b: "<<b<<'\n';
}
input:
123 34
output:
a: 123
b: 34
Pardon me for this simple question.
You can write a function that parses an array of the desired amount of input values:
use anyhow::anyhow;
use std::fmt::Display;
use std::io::{stdin, BufRead};
use std::str::FromStr;
pub fn read_and_parse<const SIZE: usize, T>() -> anyhow::Result<[T; SIZE]>
where
T: FromStr,
<T as FromStr>::Err: Display,
{
let mut buffer = String::new();
stdin().lock().read_line(&mut buffer)?;
buffer
.split_whitespace()
.map(|item| item.parse())
.collect::<Result<Vec<T>, <T as FromStr>::Err>>()
.map_err(|e| anyhow!("{e}"))?
.try_into()
.map_err(|v: Vec<_>| anyhow!("invalid size: {} != {SIZE}", v.len()))
}
fn main() {
let [a, b]: [i32; 2] = read_and_parse().expect("garbage in, garbage out");
println!("a: {a}");
println!("b: {b}");
}
You can naturally also write your own error enum, which is what anyhow spares you:
use std::fmt::{self, Debug, Display};
use std::io::{stdin, BufRead};
use std::str::FromStr;
#[derive(Debug)]
pub enum ReadOrParseError<T>
where
T: Debug + FromStr,
<T as FromStr>::Err: std::error::Error + 'static,
{
ReadError(std::io::Error),
ParseError(<T as FromStr>::Err),
InvalidLength(Vec<T>),
}
impl<T> Display for ReadOrParseError<T>
where
T: Debug + FromStr,
<T as FromStr>::Err: std::error::Error + 'static,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ReadError(error) => write!(f, "read error: {error}"),
Self::ParseError(error) => write!(f, "parse error: {error}"),
Self::InvalidLength(vec) => write!(f, "invalid length: {}", vec.len()),
}
}
}
impl<T> std::error::Error for ReadOrParseError<T>
where
T: Debug + FromStr,
<T as FromStr>::Err: std::error::Error + 'static,
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::ReadError(error) => Some(error),
Self::ParseError(error) => Some(error),
Self::InvalidLength(_) => None,
}
}
}
impl<T> From<std::io::Error> for ReadOrParseError<T>
where
T: Debug + FromStr,
<T as FromStr>::Err: std::error::Error + 'static,
{
fn from(error: std::io::Error) -> Self {
Self::ReadError(error)
}
}
pub fn read_and_parse<const SIZE: usize, T>() -> Result<[T; SIZE], ReadOrParseError<T>>
where
T: Debug + FromStr,
<T as FromStr>::Err: std::error::Error + 'static,
{
let mut buffer = String::new();
stdin().lock().read_line(&mut buffer)?;
buffer
.split_whitespace()
.map(str::parse)
.collect::<Result<Vec<T>, <T as FromStr>::Err>>()
.map_err(ReadOrParseError::ParseError)?
.try_into()
.map_err(ReadOrParseError::InvalidLength)
}
fn main() {
let [a, b]: [i32; 2] = read_and_parse().expect("garbage in, garbage out");
println!("a: {a}");
println!("b: {b}");
}