既然Map
的声明已更改,我不确定如何返回通用Map
结构。新声明是:
pub struct Map<A, B, I: Iterator<A>, F: FnMut<(A,), B>> {
// some fields omitted
}
我不确定如何从函数返回其中之一:
fn something<A: Clone, I: Iterator<A>>(iter: I) -> Map<A, (A,A), I, **what goes here**> {
iter.map(|x| (x.clone(), x))
}
我试过使用我正在使用的闭包的签名......
fn something<A: Clone, I: Iterator<A>>(iter: I) -> Map<A, (A,A), I, |A| -> (A,A)> {
iter.map(|x| (x.clone(), x))
}
但随后 rust 抱怨我需要明确的生命周期绑定。我不确定为什么我需要这个,但我还是添加了它:
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))
}
但后来我得到错误:the trait core::ops::Fn<(A,), (A, A)> is not implemented for the type 'a |A|:'a -> (A, A)
无法进一步进步,在这一点上,我只是在尝试随机的事情。有人可以帮助我了解如何使用新的Map
结构吗?
在**what goes here**
中放任何有意义的东西。您定义的闭包具有无法命名的编译器生成的类型(即,在实现抽象返回类型之前)。
由于闭包不会从其环境中捕获任何内容,因此您可以将其替换为正常功能。
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
}
但是,如果您确实需要捕获某些状态,您目前能做的最好的事情(无需诉诸拳击)就是定义您自己的实现FnMut
的类型。(此示例有一个空结构,因为没有状态; call_mut
可以通过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)
}
这是一个解决方案...
#![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)
}
我的工作假设是,您不能直接退回Fn
(或朋友),因为它是未装箱的。未装箱的闭包没有大小,因此调用函数不知道为其保留多少空间。
为了解决这个问题,我们需要返回一些确实有大小的东西:一个Box
!令人惊讶的是(我希望暂时),Box<Fn>
本身并没有实现Fn
,所以我创建了一个包装结构,我可以自己实现它。
我希望将来你可以只返回一个盒子并省去包装结构,但我继续尝试使其足够通用,现在就足够了。