2017-08-20 69 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