This question already has an answer here:
- Returning a closure from a function 3 answers
I wrote the following Rust program to print out only command-line arguments that are integers. It works perfectly:
use std::env;
fn main() {
for i in env::args().filter_map(|arg| arg.parse::<i32>().ok()) {
println!("{}", i);
}
}
I then attempted to re-write the program to abstract the filter into a function. This version does not compile.
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())
}
It produces the following compilation errors:
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`.
What I find particularly confusing is the final compilation error. I do not understand how else I might specify a closure type.
Thanks!
impl Trait
andBox<Trait>
solution can be applied to both iteratorsand closures, both of them are just traits! The difference is you have to use them in the closure case.If you want to use
impl Trait
, then your code will look like this (note thatArgs
should be passed by value):However, you usually need not expose the detail of the iterator type; therefore you can do it like this way:
What if you want to use stable Rust? Unfortunately you'll have to use boxing for now.
Why can't you describe a full type of closures, despite that you can describe an iterator like
Zip<Drain<'a, i32>, IntoIter<&'b str>>
? There are two reasons:impl Fn()
) or box (Box<Fn()>
) them if you want to return them.impl Fn() for YourType { .. }
) stably.Then why doesn't your code work? The reason is:
fn foo<T: Fn()>() { .. }
.impl Trait
.RFC 1951 will change this distinction. You will be able to use
impl Trait
in both cases.