簡體   English   中英

如何將閉包 object 存儲在結構中?

[英]How can I store a closure object in a struct?

我不知道如何將閉包 object 存儲在結構中。 arguments 和返回用於閉合 object 是已知的。 這是我的精簡代碼:

struct Instr<F>
    where F: Fn([i32;4],[i32;3]) -> [i32;4]
{
    name: String,
    op: F
}

fn main()
{
    // Simple example showing the difficulty:
    let tmp : Instr<Fn([i32;4],[i32;3]) -> [i32;4]> = Instr { name: "asd".to_string(), op: |a,b| a};

    // What I really want is something more like this:
    // let instrs = vec![
    //     Instr { name: "asdf", op: |a,b| a },
    //     Instr { name: "qwer", op: |a,b| a }
    // ];
}

坦率地說,我不明白這些錯誤是什么意思。 在我看來,這很簡單。 閉包具有類型和已知尺寸。 將其存儲在相同類型的類型字段中應該很簡單。 正確的?

嘗試添加F: ?Sized作為錯誤消息提示的並不能修復“編譯時未知大小”錯誤。

有人可以幫我正確編譯嗎?

error[E0277]: the size for values of type `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]` cannot be known at compilation time
  --> a.rs:11:15
   |
1  | struct Instr<F>
   |              - required by this bound in `Instr`
...
11 |     let tmp : Instr<Fn([i32;4],[i32;3]) -> [i32;4]> = Instr { name: "asd".to_string(), op: |a,b| a};
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]`
help: you could relax the implicit `Sized` bound on `F` if it were used through indirection like `&F` or `Box<F>`
  --> a.rs:1:14
   |
1  | struct Instr<F>
   |              ^ this could be changed to `F: ?Sized`...
2  |     where F : Fn([i32;4],[i32;3]) -> [i32;4]
   |           - ...if indirection was used here: `Box<F>`
...
5  |     op : F
   |          - ...if indirection was used here: `Box<F>`

error[E0277]: the size for values of type `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]` cannot be known at compilation time
  --> a.rs:11:55
   |
1  | / struct Instr<F>
2  | |     where F : Fn([i32;4],[i32;3]) -> [i32;4]
3  | | {
4  | |     name : String,
5  | |     op : F
6  | | }
   | |_- required by `Instr`
...
11 |       let tmp : Instr<Fn([i32;4],[i32;3]) -> [i32;4]> = Instr { name: "asd".to_string(), op: |a,b| a};
   |                                                         ^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]`

error[E0308]: mismatched types
  --> a.rs:11:92
   |
11 |     let tmp : Instr<Fn([i32;4],[i32;3]) -> [i32;4]> = Instr { name: "asd".to_string(), op: |a,b| a};
   |                                                                                            ^^^^^^^ expected trait object `dyn Fn`, found closure
   |
   = note: expected trait object `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]`
                   found closure `[closure@a.rs:11:92: 11:99]`

不同的閉包具有不同的大小,因此您不能在結構中存儲“原始閉包”或“原始特征對象”,它們必須位於指針后面,因此您可以將它們放在Box中,如下所示:

struct Instr {
    name: String,
    op: Box<dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]>,
}

fn main() {
    let instrs = vec![
         Instr { name: "asdf".into(), op: Box::new(|a,b| a) },
         Instr { name: "qwer".into(), op: Box::new(|a,b| a) }
     ];
}

操場

接受的答案完美地解決了您的用例的解決方案,但我想澄清“未調整大小”的錯誤消息以及“簡單示例”無法正常工作。

Rust 完全能夠按照問題中的定義將閉包存儲在Instr中,但是您的類型規范將其混淆了。 每個閉包的類型都是匿名的,你不能命名它。 您嘗試通過拼寫特征Fn(ARGS...) -> RESULT來指定閉包類型是錯誤的,因為在 Rust 中,當您使用預期類型的特征時,它指的是特征的動態實現,又名特征 object 特征 object 沒有大小,必須通過引用或智能指針訪問。

因此,如果您讓 Rust 推斷其類型,您可以創建一個帶有任意閉包的Instr

struct Instr<F>
    where F: Fn([i32;4],[i32;3]) -> [i32;4]
{
    name: String,
    op: F
}

fn main()
{
    // Simple example
    let tmp : Instr<_> = Instr { name: "asd".to_string(), op: |a,b| a};
}

但這不允許您創建一個Instr的向量,每個向量都有不同的閉包,因為這些Instr將具有不同的類型。 為此,您需要使用參考或Box ,如接受的答案所示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM