Parsing 使用闭包作为参数和返回值,Fn或FnMut更惯用吗?
接着,我偶然发现了一个问题,关于使用和/或产生函数/闭包的函数的边界 从中,我了解到为了方便消费者,您应该尝试将函数作为Parsing 使用闭包作为参数和返回值,Fn或FnMut更惯用吗?,parsing,rust,closures,mutable,boundary,Parsing,Rust,Closures,Mutable,Boundary,接着,我偶然发现了一个问题,关于使用和/或产生函数/闭包的函数的边界 从中,我了解到为了方便消费者,您应该尝试将函数作为Fn一次,并尽可能以Fn返回。这使调用者可以自由地传递什么以及如何处理返回的函数 在我的示例中,FnOnce是不可能的,因为我需要多次调用该函数。在尝试编译时,我发现了两种可能性: pub enum已解析(head和tail), _=>恐慌!(“称为“无条件展开”), } } pub fn是\u none(&self)->bool{ 匹配自我{ 已解析::无()=>true,
Fn一次
,并尽可能以Fn
返回。这使调用者可以自由地传递什么以及如何处理返回的函数
在我的示例中,FnOnce
是不可能的,因为我需要多次调用该函数。在尝试编译时,我发现了两种可能性:
pub enum已解析(head和tail),
_=>恐慌!(“称为“无条件展开”),
}
}
pub fn是\u none(&self)->bool{
匹配自我{
已解析::无()=>true,
_=>错误,
}
}
}
pub-fn-achar(字符:char)->impl-fn(&str)->已解析{
移动|输入|
匹配input.chars().next(){
Some(c)如果c==character=>Parsed::Some(c,&input[1..]),
_=>已解析::无(输入),
}
}
pub fn some_v1(解析器:impl fn(&str)->Parsed)->impl fn(&str)->Parsed{
移动|输入|{
让mut re=Vec::new();
让mut pos=输入;
环路{
匹配分析器(pos){
解析::一些(头、尾)=>{
再推(头);
pos=尾部;
}
已解析::无()=>中断,
}
}
解析::一些(re,pos)
}
}
pub fn some_v2(mut解析器:impl FnMut(&str)->已解析)->impl FnMut(&str)->已解析{
移动|输入|{
让mut re=Vec::new();
让mut pos=输入;
环路{
匹配分析器(pos){
解析::一些(头、尾)=>{
再推(头);
pos=尾部;
}
已解析::无()=>中断,
}
}
解析::一些(re,pos)
}
}
#[测试]
fn try_it(){
assert_eq!(一些_v1(achar(“#”)(“###comment”).unwrap(),(vec![“#”,“#”],“comment”);
assert_eq!(一些_v2(achar(“#”)(“###comment”).unwrap(),(vec![“#”,“#”],“comment”);
}
现在我不知道哪个版本更可取。版本1采用的是Fn
,它不太通用,但版本2需要其参数可变
哪一个更惯用/应该使用,背后的原理是什么
更新:感谢您对第一版的建议。我在这里更新了代码,我发现这种情况更有趣。在您编写代码时,比较
一些v1
和一些v2
,我想说版本2肯定是首选的,因为它更通用。我想不出一个解析闭包的好例子,它可以实现FnMut
,但不能实现Fn
,但是parser
作为mut
,确实没有什么不利之处——正如在关于您问题的第一条评论中所指出的,这并不以任何方式约束调用方
但是,有一种方法可以使版本1比版本2更通用(不是严格地更通用,只是部分通用),即返回impl-Fn(&str)->…
而不是impl-FnMut(&str)->…
。通过这样做,您可以得到两个函数,它们在某种程度上都比另一个受约束少,因此保留这两个函数可能更有意义:
- 具有返回类型更改的版本1的参数限制性更强(可调用函数无法更改其关联数据),但其返回类型限制性更小(您可以保证返回的可调用函数不会更改其关联数据)
- 版本2的参数限制性较小(允许可调用函数变异其关联数据),但其返回类型限制性较大(返回的可调用函数可能变异其关联数据)
mut
,并使用let mut parser=parser是一样的
作为some_v2
中的第一行。请参阅和。请参阅更新的问题,谢谢。有了这个变化,版本1似乎更适合组合(希望如此)无状态解析器,对吗?是的,没错。例如,您可以将一些_v1
传递给自身(这不是特别有用)或类似的组合器(例如fn(times:usize,parser:impl-fn(&str)->Parsed)->impl-fn(&str)->Parsed
)。