2015-05-23 18 views
7

Tôi đang cố gắng thực hiện một số chương trình bậc cao hơn trong Rust, nhưng tôi đang gặp một số khó khăn khi xử lý các đóng. Dưới đây là một đoạn mã minh họa một trong những vấn đề tôi đang gặp:"không thể di chuyển giá trị kiểu FnOnce" khi di chuyển chức năng được đóng hộp

pub enum Foo { 
    Bar(Box<FnOnce(i32)>), 
} 

pub fn app(i: i32, arg: Foo) { 
    match arg { 
     Foo::Bar(f) => f(i), 
    } 
} 

Khi tôi biên dịch đoạn mã này tôi nhận được thông báo lỗi sau:

error[E0161]: cannot move a value of type std::ops::FnOnce(i32) + 'static: the size of std::ops::FnOnce(i32) + 'static cannot be statically determined 
--> src/main.rs:7:24 
    | 
7 |   Foo::Bar(f) => f(i), 
    |      ^

Kể từ khi tôi đặt các chức năng trong một Box, tôi đã có thể nghĩ rằng sẽ đối phó với vấn đề của trình biên dịch không biết kích thước. Làm thế nào tôi có thể làm cho chương trình trên biên dịch?

Trả lời

11

Dưới đây là định nghĩa của FnOnce đặc điểm của (đơn giản hóa một chút):

pub trait FnOnce<Args> { 
    type Output; 

    fn call_once(self, args: Args) -> Self::Output; 
} 

Để gọi một đóng FnOnce, bạn cần để có thể di chuyển các giá trị đóng cửa bản thân vào sự thỉnh nguyện. Lưu ý rằng self phải là loại đóng cửa thực tế; a Box<FnOnce> là một loại hoàn toàn khác.

Kết quả là ít hoặc không thể thực hiện được.

Hiện tại, có loại trong thư viện chuẩn để xử lý chỉ tình huống này: FnBox. Thật không may, nó chỉ mới được thêm vào, và do đó không thể được sử dụng trong ổn định Rust nhưng (đó là phần "hoặc ít hơn").

Vì vậy, sự lựa chọn của bạn là:

  • Refactor mã để thay vì Box<FnOnce>, bạn duy trì kiểu đóng cửa thực tế.
  • Sử dụng Box<FnMut> để thay thế.
  • Đợi FnBox để ổn định.
  • Chuyển sang trình biên dịch hàng đêm.
+0

Cảm ơn câu trả lời.Sử dụng loại đóng cửa thực sự không phải là một lựa chọn cho tôi vì tôi cần có khả năng lưu trữ các bao đóng khác nhau trong enum. Tôi không biết làm thế nào để thực hiện công việc gợi ý 'Box ', tôi gặp lỗi khi tôi thử. Những gì tôi đã làm thay vào đó là chỉ cần nói 'Hộp '. Điều đó đã giúp tôi biên dịch ví dụ trên. Tuy nhiên, tôi không thể tạo một enum bằng cách sử dụng loại đó vì nó không phù hợp với loại đóng. Vì vậy, tôi đoán tôi còn lại với cố gắng một trình biên dịch hàng đêm. – svenningsson

+0

@svenningsson: Sử dụng 'Box ' thay thế; bởi vì 'FnMut' là" đối tượng an toàn ", bạn * có thể * gọi một từ thông qua một' Hộp' (hoặc bất kỳ sự thực sự nào).Điều duy nhất bạn không thể làm là có đóng cửa tiêu thụ các giá trị (mặc dù bạn có thể làm việc xung quanh đó với 'Option'). –

+0

Lỗi tôi nhận được khi tôi thử 'Hộp ' như sau: không thể mượn bất biến 'Nội dung hộp '' * f' là có thể thay đổi src/lib.rs: 36 Foo :: Bar (f) => f (i) – svenningsson

0

Đó là khó FnBox trở nên ổn định, nhưng trong thời gian này bạn có thể quấn F: FnOnce(...) -> ... trong một Option<F>, ràng buộc nó vào một kết thúc có thể thay đổi và unwrap và gọi nó bên (vì vậy nó hoảng sợ nếu nó được gọi là nhiều hơn một lần); đóng cửa kết quả có thể được đóng hộp là Box<FnMut(...) -> ...>, mà bạn có thể muốn bọc bằng cách nào đó để đảm bảo nó chỉ được sử dụng ("gọi") một lần.

Xem (của tôi) boxfnonce thùng.

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