2017-08-20 72 views
8

我想写一个组成两个函数的函数,最初的设计很简单,一个函数接受两个函数并返回一个组合函数,然后我可以用其他函数编写,(因为铁锈没有剩余参数)。但是我遇到了一个漫长而艰难的环境,用令人沮丧的无用编译器错误构建。如何编写防锈功能?

我的构建功能:

fn compose<'a, A, B, C, G, F>(f: F, g: G) -> Box<Fn(A) -> C + 'a> 
    where F: 'a + Fn(A) -> B + Sized, G: 'a + Fn(B) -> C + Sized 
{ 
    Box::new(move |x| g(f(x))) 
} 

我想怎样使用它:

fn main() { 
    let addAndMultiply = compose(|x| x * 2, |x| x + 2); 
    let divideAndSubtract = compose(|x| x/2, |x| x - 2); 

    let finally = compose(*addAndMultiply, *divideAndSubtract); 
    println!("Result is {}", finally(10)); 
} 

rustc不喜欢,不管我怎么努力,特质界永远不会满足。错误是:

➜ cargo run                                    
    Compiling flowtree v0.1.0 (file:///home/seunlanlege/Projects/flowtree) 
error[E0277]: the trait bound `std::ops::Fn(_) -> _: std::marker::Sized` is not satisfied 
    --> src/main.rs:11:19 
    | 
11 |  let finally = compose(*addAndMultiply, *divideAndSubtract); 
    |     ^^^^^^^ the trait `std::marker::Sized` is not implemented for `std::ops::Fn(_) -> _` 
    | 
    = note: `std::ops::Fn(_) -> _` does not have a constant size known at compile-time 
    = note: required by `compose` 

error[E0277]: the trait bound `std::ops::Fn(_) -> _: std::marker::Sized` is not satisfied 
    --> src/main.rs:11:19 
    | 
11 |  let finally = compose(*addAndMultiply, *divideAndSubtract); 
    |     ^^^^^^^ the trait `std::marker::Sized` is not implemented for `std::ops::Fn(_) -> _` 
    | 
    = note: `std::ops::Fn(_) -> _` does not have a constant size known at compile-time 
    = note: required by `compose` 

error: aborting due to 2 previous errors 

error: Could not compile `flowtree`. 

To learn more, run the command again with --verbose. 
+1

作为主要目标,你可能会寻找这样的:https://stackoverflow.com/q/36284637/1233251 –

+0

并不适用于我的情况。 –

回答

10

至于@ljedrz points out,使其工作,你只需要再次引用组成的功能:

let finally = compose(&*add_and_multiply, &*divide_and_subtract); 

(请注意,在防锈,习惯上还是会把变量名应该是snake_case)


但是,我们可以做得更好!

如果你愿意使用实验功能,#![feature(conservative_impl_trait)],从而能够使用的abstract return types,可以帮助你大大简化你的榜样,因为它可以让你跳过寿命,引用Sized约束和Box ES:

#![feature(conservative_impl_trait)] 

fn compose<A, B, C, G, F>(f: F, g: G) -> impl Fn(A) -> C 
where 
    F: Fn(A) -> B, 
    G: Fn(B) -> C, 
{ 
    move |x| g(f(x)) 
} 

fn main() { 
    let add_and_multiply = compose(|x| x * 2, |x| x + 2); 
    let divide_and_subtract = compose(|x| x/2, |x| x - 2); 

    let finally = compose(add_and_multiply, divide_and_subtract); 
    println!("Result is {}", finally(10)); 
} 

最后,因为你提到其他参数,我怀疑你真正想要的是有办法,你以灵活的方式想链组成尽可能多的功能。我写这个宏用于此目的:

#![feature(conservative_impl_trait)] 

macro_rules! compose { 
    ($last:expr) => { $last }; 
    ($head:expr, $($tail:expr), +) => { 
     compose_two($head, compose!($($tail),+)) 
    }; 
} 

fn compose_two<A, B, C, G, F>(f: F, g: G) -> impl Fn(A) -> C 
where 
    F: Fn(A) -> B, 
    G: Fn(B) -> C, 
{ 
    move |x| g(f(x)) 
} 

fn main() { 
    let add = |x| x + 2; 
    let multiply = |x| x * 2; 
    let divide = |x| x/2; 
    let intermediate = compose!(add, multiply, divide); 

    let subtract = |x| x - 2; 
    let finally = compose!(intermediate, subtract); 

    println!("Result is {}", finally(10)); 
} 
6

finally只需添加引用,也将努力:

fn main() { 
    let addAndMultiply = compose(|x| x * 2, |x| x + 2); 
    let divideAndSubtract = compose(|x| x/2, |x| x - 2); 

    let finally = compose(&*addAndMultiply, &*divideAndSubtract); 
    println!("Result is {}", finally(10)); 
} 

提领addAndMultiplydivideAndSubtract揭示性状对象,它是不是Sized;它需要包装在Box中或引用,以便将其传递给具有Sized约束的函数。

+0

你能解释为什么这个工程? –

+0

@SeunLanLege确定,完成。 – ljedrz