В Rust 1.5.x рабочим решением является:
fn main() {
let mut numbers = String::new();
io::stdin().read_line(&mut numbers).ok().expect("read error");
let numbers: Vec<i32> = numbers
.split_whitespace()
.map(|s| s.parse().unwrap())
.collect();
for num in numbers {
println!("{}", num);
}
}
Безопасная версия. Этот пропустить неудачные разборки, так что неудачный разворот не паникует. Используйте read_line
для чтения одной строки.
let mut buf = String::new();
// use read_line for reading single line
std::io::stdin().read_to_string(&mut buf).expect("");
// this one skips failed parses so that failed unwrap doesn't panic
let v: Vec<i32> = buf.split_whitespace().filter_map(|w| w.parse().ok()).collect();
Вы даже можете прочитать Vector of Vectors, как это.
let stdin = io::stdin();
let locked = stdin.lock();
let vv: Vec<Vec<i32>> = locked.lines()
.filter_map(
|l| l.ok().map(
|s| s.split_whitespace()
.filter_map(|word| word.parse().ok())
.collect()))
.collect();
Выше один работает для входов, таких как
2 424 -42 124
42 242 23 22 241
24 12 3 232 445
, а затем превращает их в
[[2, 424, -42, 124],
[42, 242, 23, 22, 241],
[24, 12, 3, 232, 445]]
filter_map
принимает замыкание, которое возвращает Option<T>
и отфильтровывает все None
s.
ok()
превращает Result<R,E>
в Option<R>
, чтобы в этом случае можно было отфильтровать ошибки.
Обновлено для Rust 1.x
Вы можете сделать что-то вроде этого:
use std::io::{self, BufRead}; // (a)
fn main() {
let reader = io::stdin();
let numbers: Vec<i32> =
reader.lock() // (0)
.lines().next().unwrap().unwrap() // (1)
.split(' ').map(|s| s.trim()) // (2)
.filter(|s| !s.is_empty()) // (3)
.map(|s| s.parse().unwrap()) // (4)
.collect(); // (5)
println!("{:?}", numbers);
}
Сначала мы берем блокировку stdin, которая позволяет работать с stdin как (по умолчанию stdin в Rust не загружен, вам нужно вызвать метод lock()
для получения буферизованной версии, но эта буферизованная версия является только одной для всех потоков в вашей программе, следовательно, доступ к ней должен быть синхронизированы).
Далее мы читаем следующую строку (1); Я использую lines()
-тератор, метод next()
возвращает Option<io::Result<String>>
, поэтому для получения только String
вам нужно unwrap()
дважды.
Затем мы разбиваем его на пробелы и обрезаем результирующие куски из дополнительных пробелов (2) удалите пустые куски, оставшиеся после обрезки (3), преобразуйте строки в i32
s (4) и соберите результат с вектором (5).
Нам также понадобятся для импорта std::io::BufRead
признака (a) для использования метода lines()
.
Если вы заранее знаете, что ваш ввод не будет содержать более одного пробела между цифрами, вы можете опустить шаг (3 ) и переместите вызов trim()
из (2) в (1):
let numbers: Vec<i32> =
reader.lock()
.lines().next().unwrap().unwrap()
.trim().split(' ')
.map(|s| s.parse().unwrap())
.collect();
Обновить
Однако ржавчина уже предлагает метод разделения строки на последовательность слова split_whitespace()
:
let numbers: Vec<i32> =
reader.read_line().unwrap().as_slice()
.split_whitespace()
.map(|s| s.parse().unwrap())
.collect()
split_whitespace()
на самом деле представляют собой комбинацию split()
и filter()
, как и в моем оригинале пример. Он использует функцию в аргументе split()
, которая проверяет разные типы пробелов, а не только пробельные символы. Вы можете найти его источник здесь .