我编写了以下Rust程序,只打印出整数的命令行参数。它完美地运作:
use std::env;
fn main() {
for i in env::args().filter_map(|arg| arg.parse::<i32>().ok()) {
println!("{}", i);
}
}
然后我尝试重新编写程序以将过滤器抽象为函数。此版本无法编译。
use std::env::Args;
use std::env;
use std::iter::FilterMap;
// Version 2
fn main() {
for i in nums(&env::args()) {
println!("{}", i);
}
}
fn nums<F: Fn(String) -> Option<i32>>(args: &Args) -> FilterMap<Args,F> {
args.filter_map(|arg| arg.parse::<i32>().ok())
}
它产生以下编译错误:
Compiling iterator_return_type v0.1.0 (file:///Users/gabriel/AllProjects/SentimentAnalysis/iterator_return_type)
error[E0282]: type annotations needed
--> src/main.rs:16:9
|
16 | for i in nums(&env::args()) {
| ^ cannot infer type for `_`
error: the type of this value must be known in this context
--> src/main.rs:22:27
|
22 | args.filter_map(|arg| arg.parse::<i32>().ok())
| ^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> src/main.rs:22:21
|
22 | args.filter_map(|arg| arg.parse::<i32>().ok())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found closure
|
= note: expected type `F`
found type `[closure@src/main.rs:22:21: 22:50]`
error: aborting due to previous error(s)
error: Could not compile `iterator_return_type`.
我发现特别令人困惑的是最终的编译错误。我不明白我怎么可能指定一个闭包类型。
谢谢!
答案 0 :(得分:2)
impl Trait
和Box<Trait>
解决方案可以应用于迭代器和闭包,它们都只是特征!区别在于你必须在闭包案例中使用它们。
如果您想使用impl Trait
,那么您的代码将如下所示(请注意Args
应按值传递):
#![feature(conservative_impl_trait)]
use std::env::Args;
use std::env;
use std::iter::FilterMap;
fn main() {
for i in nums(env::args()) {
println!("{}", i);
}
}
fn nums(args: Args) -> FilterMap<Args, impl FnMut(String) -> Option<i32>> {
args.filter_map(|arg| arg.parse::<i32>().ok())
}
但是,通常不需要公开迭代器类型的细节;因此你可以这样做:
fn nums(args: Args) -> impl Iterator<Item = i32> {
args.filter_map(|arg| arg.parse::<i32>().ok())
}
如果您想使用稳定的Rust怎么办?不幸的是,你现在必须使用拳击。
fn nums(args: Args) -> Box<Iterator<Item = i32>> {
Box::new(args.filter_map(|arg| arg.parse::<i32>().ok()))
}
为什么你不能描述完整类型的闭包,尽管你可以描述像Zip<Drain<'a, i32>, IntoIter<&'b str>>
这样的迭代器?有两个原因:
impl Fn()
)或框(Box<Fn()>
)。impl Fn() for YourType { .. }
)。那为什么你的代码不起作用?原因是:
fn foo<T: Fn()>() { .. }
。impl Trait
。 RFC 1951将改变这种区别。在这两种情况下,您都可以使用impl Trait
。