Возможное решение:
use anyhow::Result;
use std::io;
fn main() -> Result<()> {
// Read from stdin
let mut input = String::new();
io::stdin().read_line(&mut input)?;
// Split input
let parts = input.split_whitespace().collect::<Vec<_>>();
// Parse and print
let a: i64 = parts[0].parse()?;
let b: i64 = parts[1].parse()?;
println!("a: {a}");
println!("b: {b}");
// Return Ok
Ok(())
}
Вы можете написать функцию, которая анализирует массив желаемого количества входных значений:
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}");
}
Вы, естественно, также можете написать свое собственное перечисление ошибок, что в любом случае избавит вас:
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}");
}
Круто, но есть ли способ без ящика?
Обновленный ответ с перечислением самостоятельно написанных ошибок.
Кроме того, принятый вами ответ использует тот же сторонний ящик.
Да, он вышел первым, и я заставил его работать без стороннего ящика, так что я все равно принял его, спасибо!
Это не поддерживается стандартной библиотекой: если вы хотите прочитать со стандартного ввода (или файла, если на то пошло), вы
read
(или другие служебные функции) со стандартного ввода, тогда вы анализируете себя. На грузе есть ящики с функциями типа scanf (обычно инвертирующими собственныеformat
ржавчины, а не printf, очевидно). Поискscanf
их обнаружит.