问题
I'm not sure how return a generic Map struct now that the declaration for Map has changed. The new declaration is:
pub struct Map<A, B, I: Iterator<A>, F: FnMut<(A,), B>> {
// some fields omitted
}
I'm not sure how to return one of these from a function:
fn something<A: Clone, I: Iterator<A>>(iter: I) -> Map<A, (A,A), I, **what goes here**> {
iter.map(|x| (x.clone(), x))
}
I've tried using the signature of the closure I'm using...
fn something<A: Clone, I: Iterator<A>>(iter: I) -> Map<A, (A,A), I, |A| -> (A,A)> {
iter.map(|x| (x.clone(), x))
}
But then rust complains that I need an explicit lifetime bound. I'm not sure why I need this, but I add it anyway:
fn something<'a, A: Clone, I: Iterator<A>>(iter: I) -> Map<A, (A,A), I, |A|:'a -> (A,A)> {
iter.map(|x| (x.clone(), x))
}
But then I get the error: the trait core::ops::Fn<(A,), (A, A)> is not implemented for the type 'a |A|:'a -> (A, A)
I haven't been able to progress any further, and at this point I'm just trying random things. Can someone help me understand how to use the new Map struct?
回答1:
You can't put anything meaningful in **what goes here**. The closure you define has a compiler-generated type that you can't name (that is, until abstract return types are implemented).
Since your closure doesn't capture anything from its environment, you can replace it with a normal function.
use std::iter::Map;
fn duplicate<T: Clone>(a: T) -> (T, T) {
(a.clone(), a)
}
fn something<A: Clone, I: Iterator<A>>(iter: I) -> Map<A, (A,A), I, fn(A) -> (A, A)> {
iter.map(duplicate as fn(A) -> (A, A)) // cast required since PR #19891
}
However, if you do need to capture some state, the best you can do (without resorting to boxing) for the moment is to define your own type that implements FnMut. (This example has an empty struct because there's no state; call_mut could access and alter the struct's state through self.)
#![feature(unboxed_closures)]
use std::iter::Map;
struct Duplicate;
impl<T: Clone> FnMut(T) -> (T, T) for Duplicate {
extern "rust-call" fn call_mut(&mut self, (a,): (T,)) -> (T, T) {
(a.clone(), a)
}
}
fn something<A: Clone, I: Iterator<A>>(iter: I) -> Map<A, (A,A), I, Duplicate> {
iter.map(Duplicate)
}
回答2:
Here's a solution...
#![feature(unboxed_closures)]
use std::iter::Map;
use std::slice::Items;
// Box<Fn> should probably work "out-of-the-box", but I couldn't get it to...
struct Z<'a, Args, Result>(Box<Fn<Args, Result> + 'a>);
// So let's define it ourselves!
impl <'a, Args, Result> std::ops::Fn<Args, Result> for Z<'a, Args, Result> {
extern "rust-call" fn call(&self, args: Args) -> Result {
self.0.call(args)
}
}
fn do_it(a: &[int]) -> Map<&int, int, Items<int>, Z<(&int,), int>> {
// Needed to specify the parameter type, too
a.iter().map(Z(box |&: x: &int| *x + 1))
}
fn main() {
let a = vec!(1 , 2 , 3);
let b = do_it(a.as_slice());
let c: Vec<_> = b.collect();
println!("{}" , c)
}
My working hypothesis is that you cannot return a Fn (or friend) directly, because it is unboxed. Unboxed closures aren't sized, so the calling function doesn't know how much space to reserve for it.
To work around that, we need to return something that does have a size: a Box! Surprisingly (and I'd hope temporarily), Box<Fn> doesn't itself implement Fn, so I created a wrapper struct that I could implement it myself.
I'd expect that in the future, you'd be able to just return a box and dispense with the wrapper struct, but I went ahead and tried to make it generic enough to suffice for now.
来源:https://stackoverflow.com/questions/27496278/how-to-return-a-generic-map-struct