2017-08-20 17 views
8

Tôi đang cố gắng viết một hàm gồm hai hàm, thiết kế ban đầu khá đơn giản, một hàm có hai hàm và trả về một hàm được tạo mà sau đó tôi có thể soạn với các hàm khác, (vì gỉ không có tham số còn lại). Nhưng tôi đã chạy vào một bức tường cứng dài được xây dựng với lỗi trình biên dịch không hữu ích bực bội.Làm thế nào để soạn chức năng trong gỉ?

chức năng soạn của tôi:

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))) 
} 

Làm thế nào tôi muốn sử dụng nó:

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 không như vậy, không có vấn đề gì tôi cố gắng, giới hạn đặc điểm là không bao giờ hài lòng. Lỗi này là:

➜ 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

Đối với các mục tiêu chính, bạn có thể tìm kiếm này: https://stackoverflow.com/q/36284637/1233251 –

+0

không áp dụng cho trường hợp của tôi. –

Trả lời

10

Như @ljedrz points out, để làm cho nó hoạt động, bạn chỉ cần tham khảo các chức năng bao gồm một lần nữa:

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

(Lưu ý rằng trong Rust, ước dictates rằng tên biến phải ở trong snake_case)


Tuy nhiên, chúng tôi có thể cải thiện điều này!

Nếu bạn sẵn sàng để sử dụng tính năng thử nghiệm, #![feature(conservative_impl_trait)], cho phép việc sử dụng các abstract return types, có thể giúp bạn đơn giản hóa ví dụ của bạn rất nhiều, vì nó cho phép bạn bỏ qua các kiếp sống, tài liệu tham khảo, Sized trở ngại và 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)); 
} 

Cuối cùng, vì bạn đề cập đến các tham số còn lại, tôi nghi ngờ rằng những gì bạn thực sự muốn là có cách tạo chuỗi theo nhiều chức năng như bạn muốn một cách linh hoạt. Tôi đã viết macro này cho mục đích này:

#![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

Chỉ cần thêm tài liệu tham khảo trong finally và nó sẽ làm việc:

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)); 
} 

dereferencing addAndMultiply hoặc divideAndSubtract phát hiện ra một đối tượng đặc điểm mà không phải là Sized; nó cần phải được bọc trong một Box hoặc được tham chiếu để nó được chuyển đến một hàm có ràng buộc Sized.

+0

Bạn có thể giải thích lý do tại sao tính năng này hoạt động không? –

+0

@SeunLanLege chắc chắn, đã xong. – ljedrz

Các vấn đề liên quan