functional-programming - 有没有更好的功能方法来处理带有错误检查的向量?
问题描述
我正在学习 Rust,想知道如何改进下面的代码。
我有一个形式的元组向量(u32, String)
。这些u32
值表示行号,String
s 是相应行上的文本。只要所有字符串值都可以成功解析为整数,我想返回一个Ok<Vec<i32>>
包含刚刚解析的值的String
值,但如果不是,我想返回某种形式的错误(只是Err<String>
下面示例中的一个)。
我正在尝试学习避免可变性并在适当的情况下使用功能样式,如果只需要这些,上面的功能就很容易做到。这是我在这种情况下想出的:
fn data_vals(sv: &Vec<(u32, String)>) -> Result<Vec<i32>, String> {
sv.iter()
.map(|s| s.1.parse::<i32>()
.map_err(|_e| "*** Invalid data.".to_string()))
.collect()
}
但是,小问题是我想为每个无效值(而不仅仅是第一个)打印一条错误消息,并且错误消息应该包含行号和有问题的元组中的字符串值。
我已经设法用以下代码做到了:
fn data_vals(sv: &Vec<(u32, String)>) -> Result<Vec<i32>, String> {
sv.iter()
.map(|s| (s.0, s.1.parse::<i32>()
.or_else(|e| {
eprintln!("ERROR: Invalid data value at line {}: '{}'",
s.0, s.1);
Err(e)
})))
.collect::<Vec<(u32, Result<i32, _>)>>() // Collect here to avoid short-circuit
.iter()
.map(|i| i.1
.clone()
.map_err(|_e| "*** Invalid data.".to_string()))
.collect()
}
这可行,但看起来相当混乱和麻烦 - 特别是collect()
在中间键入以避免短路,因此所有错误都被打印出来。这个clone()
调用也很烦人,我不确定为什么需要它 - 编译器说我要移出借用的内容,但我不确定要移走什么。有没有办法可以更干净地完成?还是我应该回到更程序化的风格?当我尝试时,我最终得到了可变变量和一个指示成功和失败的标志,这似乎不太优雅:
fn data_vals(sv: &Vec<(u32, String)>) -> Result<Vec<i32>, String> {
let mut datavals = Vec::new();
let mut success = true;
for s in sv {
match s.1.parse::<i32>() {
Ok(v) => datavals.push(v),
Err(_e) => {
eprintln!("ERROR: Invalid data value at line {}: '{}'",
s.0, s.1);
success = false;
},
}
}
if success {
return Ok(datavals);
} else {
return Err("*** Invalid data.".to_string());
}
}
有人可以告诉我最好的方法吗?我应该坚持这里的程序风格吗?如果可以,可以改进吗?还是有更清洁的功能方式来做到这一点?还是两者的混合?任何建议表示赞赏。
解决方案
我认为这就是partition_map()
itertools 的用途:
use itertools::{Either, Itertools};
fn data_vals<'a>(sv: &[&'a str]) -> Result<Vec<i32>, Vec<(&'a str, std::num::ParseIntError)>> {
let (successes, failures): (Vec<_>, Vec<_>) =
sv.iter().partition_map(|s| match s.parse::<i32>() {
Ok(v) => Either::Left(v),
Err(e) => Either::Right((*s, e)),
});
if failures.len() != 0 {
Err(failures)
} else {
Ok(successes)
}
}
fn main() {
let numbers = vec!["42", "aaaezrgggtht", "..4rez41eza", "55"];
println!("{:#?}", data_vals(&numbers));
}
推荐阅读
- python - 将本地csv文件导入python时出错
- bash - Zenity 图像编辑器
- terminal - 不允许使用 OSX High Sierra Sym Link
- jenkins - 在 Powershell 脚本中传递 Jenkins 环境变量
- sql - 使用 tsql 根据各种百分比分布记录
- c++ - c ++将指针从构造函数传递给构造函数
- python - MNIST 上的 TensorFlow 教程
- javascript - 遍历对象值 - javascript
- jquery - Jquery:如何为当前 TD 设置一些值
- ruby-on-rails - ActiveStorage 不会裁剪变体