我一直在努力建立一个拥有用户输入功能的课程。虽然我实际上可以让它自己工作,但当我尝试提供一个使用默认函数的创建方法时会出现问题。说明问题的玩具示例如下所示,可以在此Playground Link
找到fn main() {
let a = Apply::mini(2);
println!("{}", a.apply());
}`
struct Apply<F, I> {
f: F,
i: I,
}
impl<F, I> Apply<F, I> {
fn new(f: F, i: I) -> Apply<F, I> {
Apply{ f: f, i: i }
}
}
impl<F, I> Apply<F, I> where F: Fn(I) -> i32 {
fn apply(self) -> i32 {
(self.f)(self.i)
}
}
impl Apply<Fn(i32) -> i32, i32> {
fn mini(i: i32) -> Apply<Fn(i32) -> i32, i32> {
Apply::new(|x| x + 1, i)
}
}
这个实现正确地抱怨Fn(i32) - &gt; i32未分级。我能想到绕过它的唯一方法就是把它作为一个类型参数拉出来,但这似乎也不起作用。
答案 0 :(得分:3)
Rust中的未装箱闭包实现为实现某些特征的匿名类型。 “匿名”当然意味着它们无法命名 - 因此不可能(at least now)通过函数的值返回未装箱的闭包。
有两种方法可以解决这个特定问题。首先,因为mini()
中的闭包不会捕获任何内容,所以可以使用常规函数:
impl Apply<fn(i32) -> i32, i32> {
fn mini1(i: i32) -> Apply<fn(i32) -> i32, i32> {
fn add_one(x: i32) -> i32 { x + 1 }
Apply::new(add_one, i)
}
}
其次,如果您确实需要使用捕获闭包,则必须使用Box
:
impl Apply<Box<Fn(i32) -> i32>, i32> {
fn mini2(i: i32) -> Apply<Box<Fn(i32) -> i32>, i32> {
Apply::new(Box::new(|x| x + 1), i)
}
}
我不知道为什么,但为了这个工作我必须专门为盒子实现apply2()
方法(这对我来说真的看起来像个bug):
impl<I> Apply<Box<Fn(I) -> i32>, I> {
fn apply2(self) -> i32 {
(self.f)(self.i)
}
}
(全部试试here)
更新: here是@ker的代码链接,不需要第二个apply
方法。它使用Deref
的一个很好的技巧,允许apply()
与盒装特征对象一起使用。