У Rust есть что-то вроде scanf?

Мне нужно проанализировать файл с каждой строкой

<string><space><int><space><float>

например.

abce 2 2.5

В C я бы сделал:

scanf("%s%d%f", &s, &i, &f);

Как я могу сделать это легко и идиоматично в Rust?

Ответ 1

Стандартная библиотека не предоставляет эту функцию. Вы можете написать свой собственный макрос.

macro_rules! scan {
    ( $string:expr, $sep:expr, $( $x:ty ),+ ) => {{
        let mut iter = $string.split($sep);
        ($(iter.next().and_then(|word| word.parse::<$x>().ok()),)*)
    }}
}

fn main() {
    let output = scan!("2 false fox", char::is_whitespace, u8, bool, String);
    println!("{:?}", output); // (Some(2), Some(false), Some("fox"))
}

Второй входной аргумент для макроса может быть a & str, char или соответствующей функцией закрытия /. Указанные типы должны реализовывать свойство FromStr.

Обратите внимание, что я поставил это вместе быстро, чтобы он не был протестирован полностью.

Ответ 2

Вы можете использовать ящик text_io для входа типа scanf, который имитирует макрос print! в синтаксисе

#[macro_use] extern crate text_io;

fn main() {
    // note that the whitespace between the {} is relevant
    // placing any characters there will ignore them but require
    // the input to have them
    let (s, i, j): (String, i32, f32);
    scan!("{} {} {}\n", s, i, j);
}

Вы также можете разбить его на 3 команды:

#[macro_use] extern crate text_io;

fn main() {
    let a: String = read!("{} ");
    let b: i32 = read!("{} ");
    let c: f32 = read!("{}\n");
}

Ответ 3

Ящик scan_fmt предлагает другую альтернативу. Он поддерживает простые шаблоны, возвращает свой вывод в параметрах и имеет синтаксис, который лучше всего подходит для text_io:

#[macro_use] extern crate scan_fmt;

fn main() {
    let (s, i, j) = scan_fmt!("abce 2 2.5", "{} {d} {f}\n", String, i32, f32);
    println!("{} {} {}", s.unwrap(), i.unwrap(), j.unwrap());
}