Ввод дескриптора Rust для нескольких переменных в одной строке ввода

Я хочу прочитать вводимые данные в Rust, как в этом примере на C++:

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';
}

вход:

123 34

выход:

a: 123
b: 34

Простите меня за этот простой вопрос.

Это не поддерживается стандартной библиотекой: если вы хотите прочитать со стандартного ввода (или файла, если на то пошло), вы read (или другие служебные функции) со стандартного ввода, тогда вы анализируете себя. На грузе есть ящики с функциями типа scanf (обычно инвертирующими собственные format ржавчины, а не printf, очевидно). Поиск scanf их обнаружит.

Masklinn 23.07.2024 13:28
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
1
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Возможное решение:

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}");
}

Детская площадка

Круто, но есть ли способ без ящика?

Loaf 25.07.2024 03:47

Обновленный ответ с перечислением самостоятельно написанных ошибок.

Richard Neumann 25.07.2024 08:24

Кроме того, принятый вами ответ использует тот же сторонний ящик.

Richard Neumann 25.07.2024 08:40

Да, он вышел первым, и я заставил его работать без стороннего ящика, так что я все равно принял его, спасибо!

Loaf 25.07.2024 17:59

Другие вопросы по теме