How to return a generic Map struct?

∥☆過路亽.° 提交于 2019-12-07 07:08:39

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!