Rust:如何在first Err或None上短路退出迭代器方法链?
考虑一系列迭代器方法:Rust:如何在first Err或None上短路退出迭代器方法链?,rust,iterator,monads,short-circuiting,Rust,Iterator,Monads,Short Circuiting,考虑一系列迭代器方法: .iter().a().b().c() 其中a生成类型为Option(或Result)的值。当a产生None(或Err())时,是否有办法让整个链返回None(或Err()) 详细示例 给定函数有效(识别无意义的输入)和接受(一个 任意选择标准): 类型T=u8; 类型ERR=u8; fn有效(x:&T)->结果{ 如果*xbool{ 如果*x>9{panic!(“{}应该被验证器拒绝”)} *x%2==0 } 我想写一个函数 fn计数\u已接受(数据:&[T])->
.iter().a().b().c()
其中a
生成类型为Option
(或Result
)的值。当a
产生None
(或Err()
)时,是否有办法让整个链返回None
(或Err()
)
详细示例
给定函数<代码>有效<代码>(识别无意义的输入)和<代码>接受<代码>(一个
任意选择标准):
类型T=u8;
类型ERR=u8;
fn有效(x:&T)->结果{
如果*x<10{Ok(*x)}否则{Err(*x)}
}
fn接受(x:&T)->bool{
如果*x>9{panic!(“{}应该被验证器拒绝”)}
*x%2==0
}
我想写一个函数
fn计数\u已接受(数据:&[T])->结果
哪个
- 在中遇到第一个无效元素时,立即返回
输入数据Err(Err)
- 如果所有元素都有效,则返回包含值计数的
满足Ok(usize)
标准的接受
fn计数循环(数据:&[T])->结果{
让mut count=0;
对于数据中的项{
有效(&项)?;
如果接受(&item){count+=1}
}
好(计数)
}
这些试验证明,其似乎按照要求工作:
宏规则!测试{
($count:path)=>{
#[test]fn empty(){assert_eq!($count(&[]),Ok(0))}
#[test]fn all_ok_和_accepted(){assert_eq!($count(&[2,6]),ok(2))}
#[test]fn all_ok_some_rejected(){assert_eq!($count(&[2,3]),ok(1))}
#[test]fn one_invalid(){assert_eq!($count(&[12]),Err(12))}
#[test]fn stop_on_first_invalid(){assert_eq!($count(&[2,13,6,12,5]),Err(13))}
}
}
mod test_loop{testem!{super::count_loop}
我想了解是否/如何使用
迭代器而不是循环
考虑一个相关但更简单的问题:如果有任何数据无效,请退出
立即输出,否则将所有数据收集到向量中。换句话说,
从上一个问题中删除accept
条件
这个问题有一个非常令人满意的解决方案,因为迭代器的fromtiterator
结果的实施
负责提前终止:
fn相关(数据:&[T])->结果{
数据.国际热核实验堆()
.map(有效)
.collect()
}
mod test_相关{
#[测试]
fn stop_on_first_invalid(){assert_eq!(super::related(&[2,13,6,12,5]),Err(13))}
}
这里是相关
的扩展,它通过了与计数循环
相同的测试:
fn count\u via\u vec(数据:&[T])->结果{
好(数据)
.国际热核实验堆(iter)
.map(有效)
.filter(|x | x.is_err()| | accept(&x.unwrap()))
收集::()?
.len())
}
mod test_vvec{testem!{super::count_via_vec}}
但是:该解决方案在计数循环方面有许多缺点:
- 过滤条件非常嘈杂
- 当第一个无效项出现时,仍需要执行筛选步骤
已识别(与原始循环实现不同):出现
?
如果有意义的话,比应该的晚2行
- 矢量被不必要地填充(除非锈菌会导致某些冷却)
优化,我还没有意识到),所以空间复杂性从
O(1)至O(N)
最后一点通常通过替换
.collect::()?.len())
与.count()
取消无效案例识别的进一步不利影响:它们
这些都被简单地算作成功,这可以从这次失败的测试中看出
实施:
fn计数迭代(数据:&[T])->结果{
Ok(数据
.国际热核实验堆(iter)
.map(有效)
.filter(|x | x.is_err()| | accept(&x.unwrap()))
.count())
}
mod test_iter{testem!{super::count_iterate}
您能推荐一些在迭代器方法链中提前返回的机制吗
这可以在这样的情况下使用?您可能正在寻找的是,其中T:Sum
的结果有一个impl Sum,而所有基本整数也有Sum
的impl
因此,以下方法将起作用:
fn valid(x: &u32) -> Result<u32, u32> {
if *x < 10 { Ok(1) } else { Err(*x) }
}
fn count(x: &[u32]) -> Result<u32, u32> {
x.iter()
.map(valid)
.sum()
}
fn main() {
println!("{:?}", count(&[13,1,2,3]));
}
fn有效(x:&u32)->结果{
如果*x<10{Ok(1)}否则{Err(*x)}
}
fn计数(x:&[u32])->结果{
x、 iter()
.map(有效)
.sum()
}
fn main(){
println!(“{:?}”,count(&[13,1,2,3]);
}
正如Sum
上的文档所说,如果遇到错误,这将使迭代器短路。这将包括短路链式迭代器。您可能要查找的是,其中T:Sum
的结果有一个impl Sum,而所有基本整数也有Sum
的impl
因此,以下方法将起作用:
fn valid(x: &u32) -> Result<u32, u32> {
if *x < 10 { Ok(1) } else { Err(*x) }
}
fn count(x: &[u32]) -> Result<u32, u32> {
x.iter()
.map(valid)
.sum()
}
fn main() {
println!("{:?}", count(&[13,1,2,3]));
}
fn有效(x:&u32)->结果{
如果*x<10{Ok(1)}否则{Err(*x)}
}
fn计数(x:&[u32])->结果{
x、 iter()
.map(有效)
.sum()
}
fn main(){
println!(“{:?}”,count(&[13,1,2,3]);
}
正如Sum
上的文档所说,如果遇到错误,这将使迭代器短路。这将包括短路链式迭代器。您是否尝试了try\u
迭代器方法<代码>为每一个进行尝试
似乎与您要查找的内容相似。你找到干净的解决方案了吗?谢谢我发现了一些朝着正确方向迈出的一步,但由于我已经远离铁锈好几个月了,我的记忆非常模糊。第一个是。另一个是,在某些情况下,错误的实现实际上对j