4 10 30 232312
),我想要读取并转换为整数数组(或向量),但我找不到正确的方法。目前为止,我的代码是:
我正在使用STDIN输入一串数字(例如4 10 30 232312
),我想要读取并转换为整数数组(或向量),但我找不到正确的方法。目前为止,我的代码是:
use std::io;
fn main() {
let mut reader = io::stdin();
let numbers = reader.read_line().unwrap();
}
4 10 30 232312
),我想要读取并转换为整数数组(或向量),但我找不到正确的方法。目前为止,我的代码是:
我正在使用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
(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()
实际上只是我原来示例中 split()
和 filter()
的结合。它使用了一个 split()
函数参数,该参数检查不同种类的空格字符,而不仅仅是空格字符。
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.
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
。
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))?;
.words()
方法(比只使用空格稍微更通用一些)。 - huonsplit_whitespace()
而不是words()
。当然,现在也没有int
了。 - Vladimir Matveevread_line()
;我建议使用lines().next()
代替。 - Vladimir Matveev