函数逻辑大概像这样:
const sum = (f, g) => x => f(x) + g(x);
目前我能按文档( https://doc.rust-lang.org/book/closures.html )做成下面这样,但是总是编译不过。
fn sum<F, G>(f: &'static F, g: &'static G) -> Box<Fn(i32) -> i32>
where F: Fn(i32) -> i32,
G: Fn(i32) -> i32
{
Box::new(move |x| f(x) + g(x))
}
let f1 = |x: i32| x * x;
let f2 = |x: i32| x * 2 + 1;
let a = sum(&f1, &f2);
println!("{}", a(1i32));
println!("{}", a(2i32));
println!("{}", a(3i32));
1
Kilerd 2016-12-21 13:05:22 +08:00 via iPhone
我也懵。
|
2
dogfeet 2017-02-26 23:25:49 +08:00 1
声明周期标记的有问题, sum 中的 2 个参数都被标记为 ’ static 了,实际传入的壁报声明周期并不是 'static 的。而且返回的 Box 实际上是引用了传入的 2 个参数,实际上返回值这里有个非常绕的问题。正常 move 的 closure 会使用非引用的形式捕获,但是由于你传入的是 2 个 trait object ,所以无论怎样返回的 Box 都有生命周期的依赖。
改写了一下,下面的形式可以通过,总之, Rust 的闭包我是真心感觉蛋疼: ```rust fn sum<'a, F, G>(f: &'a F, g: &'a G) -> Box<(Fn(i32) -> i32) + 'a> where F: Fn(i32) -> i32, G: Fn(i32) -> i32 { Box::new(move |x: i32| f(x) + g(x)) } fn main() { let f1 = |x: i32| x * x; let f2 = |x: i32| x * 2 + 1; let a = sum(&f1, &f2); println!("{}", a(1i32)); println!("{}", a(2i32)); println!("{}", a(3i32)); } ``` |
3
vghdjgh OP @dogfeet
感谢 后来我改成全 box 的形式,也可以通过编译: let sum = |f: Box<Fn(i32) -> i32>, g: Box<Fn(i32) -> i32>| Box::new(move |x| f(x) + g(x)); let a = sum(Box::new(|x| x * x), Box::new(|x| 2 * x + 1)); // 应该是 x * x + x * 2 + 1 println!("{}", a(1)); // 应该是 4 println!("{}", a(2)); // 应该是 9 println!("{}", a(3)); // 应该是 16 |
4
dogfeet 2017-02-27 11:35:32 +08:00
@vghdjgh 是的。 Box 也是可以的。
其实这么写挺蛋疼的,必须要用 trait object ,因为闭包的类型是匿名的。用 Map 类似的结构,如果闭包是传入的,那么传入的类型是可以推倒出来的,如果没有传入,就很麻烦了。 其实这个需求很早就有在讨论了,开启 conservative_impl_trait 就可以使用 impl trait 这种方式约束返回类型了。 #![feature(conservative_impl_trait)] fn sum<F, G>(f: F, g: G) -> Box<(impl Fn(i32) -> i32)> where F: Fn(i32) -> i32, G: Fn(i32) -> i32 { Box::new(move |x: i32| f(x) + g(x)) } fn main() { let f1 = |x: i32| x * x; let f2 = |x: i32| x * 2 + 1; let a = sum(f1, f2); println!("{}", a(1i32)); println!("{}", a(2i32)); println!("{}", a(3i32)); } |