我在 STDIN 上写了一串数字(例如4 10 30 232312
),我想读取它并转换为整数数组(或向量),但我找不到正确的方法。到目前为止,我有:
use std::io;
fn main() {
let mut reader = io::stdin();
let numbers = reader.read_line().unwrap();
}
我在 STDIN 上写了一串数字(例如4 10 30 232312
),我想读取它并转换为整数数组(或向量),但我找不到正确的方法。到目前为止,我有:
use std::io;
fn main() {
let mut reader = io::stdin();
let numbers = reader.read_line().unwrap();
}
你可以这样做:
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);
}
首先,我们锁定标准输入,让您可以将标准输入用作缓冲阅读器。默认情况下,Rust 中的标准输入是无缓冲的;您需要调用该lock()
方法来获取它的缓冲版本,但是这个缓冲版本是程序中所有线程的唯一版本,因此应该同步对它的访问。
接下来,我们阅读下一行(1);我正在使用其方法返回的lines()
迭代器,因此只需两次即可获得。next()
Option<io::Result<String>>
String
unwrap()
然后我们用空格分割它并从额外的空白中修剪结果块 (2),删除修剪后留下的空块 (3),将字符串转换为i32
s (4) 并将结果收集到向量 (5)。
我们还需要导入std::io::BufRead
trait (a) 才能使用该lines()
方法。
如果您事先知道您的输入不会在数字之间包含一个以上的空格,您可以省略步骤 (3) 并将trim()
调用从 (2) 移动到 (1):
let numbers: Vec<i32> =
reader.lock()
.lines().next().unwrap().unwrap()
.trim().split(' ')
.map(|s| s.parse().unwrap())
.collect();
Rust 还提供了一种将字符串拆分为一系列以空格分隔的单词的方法,称为split_whitespace()
:
let numbers: Vec<i32> =
reader.read_line().unwrap().as_slice()
.split_whitespace()
.map(|s| s.parse().unwrap())
.collect()
split_whitespace()
实际上只是 and 的组合split()
,filter()
就像我原来的例子一样。它使用一个split()
函数参数来检查不同类型的空格,而不仅仅是空格字符。
在 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().expect("parse error"))
.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() // split string into words by whitespace
.filter_map(|w| w.parse().ok()) // calling ok() turns Result to Option so that filter_map can discard None values
.collect(); // collect items into Vector. This determined by type annotation.
你甚至可以像这样阅读 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>
在这种情况下可以过滤错误。
更安全的版本Dulguun Otgon
只是跳过所有错误。如果您不想跳过错误,请考虑使用下一种方法。
fn parse_to_vec<'a, T, It>(it: It) -> Result<Vec<T>, <T as FromStr>::Err>
where
T: FromStr,
It: Iterator<Item = &'a str>,
{
it.map(|v| v.parse::<T>()).fold(Ok(Vec::new()), |vals, v| {
vals.and_then(|mut vals| {
v.and_then(|v| {
vals.push(v);
Ok(vals)
})
})
})
}
在使用它时,您可以按照通常的恐慌方式expect
let numbers = parse_to_vec::<i32, _>(data_str.trim().split(" "))
.expect("can't parse data");
或更智能的方式转换为结果
let numbers = parse_to_vec::<i32, _>(data_str.trim().split(" "))
.map_err(|e| format!("can't parse data: {:?}", e))?;