簡體   English   中英

為什么相同簽名的 Rust 閉包不具有相同的類型?

[英]Why don't Rust closures of the same signature have the same type?

根據這個答案,Rust 將具有相同返回類型的異步塊和閉包視為不同類型。

為什么 Rust 將具有相同簽名的閉包視為不同類型? 這是理論上的限制還是編譯器的限制?

在 Haskell 中,它們的處理方式相同。

AFAIK,Haskell 在堆上分配它們。 這相當於 Rust 中的Box<dyn Fn()> 由於您將它們裝箱,因此您知道大小將始終為2*usize (一個數據指針和一個 vtable 指針)。

默認情況下,Rust 不會裝箱。 相反,每個閉包都會獲得一個新的、不可命名的結構,其中包含所有捕獲的變量。 例如,以下內容:

let a: i32 = 123;
let closure = |b: i32| -> i32 { a + b };

翻譯成類似的東西(不完全是,但沒關系):

struct Closure { a: i32 }
impl FnOnce<(i32,)> for Closure {
    type Output = i32;
    extern "rust-call" fn call_once(self, (b,): (i32,)) -> i32 {
        self.a + b
    }
}

這樣效率更高,本質上使閉包為零成本,但我們要付出的代價是不同的閉包在內存中有不同的布局。 因此,即使它們具有相同的簽名,它們也不相等,因此您不能返回其中之一。

此外,即使它們碰巧具有相同的布局,您仍然不能返回不同的閉包類型,因為閉包是靜態分派的。 我們不依賴 vtable 來查找閉包代碼,而是直接調用它。 同樣,這使它們成為零成本,這對 Rust 很重要,但意味着如果它們不是同一個閉包,您將不知道要調用什么代碼。

有一種特殊情況:不捕獲任何內容的閉包可以轉換為函數指針。 這就像一個沒有數據指針的 vtable,因為我們知道它們沒有數據:

let closure = if condition {
    || {} as fn()
} else {
    || {} as fn()
};

暫無
暫無

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

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