根据这个答案,Rust 将具有相同返回类型的异步块和闭包视为不同类型。
为什么 Rust 将具有相同签名的闭包视为不同类型?这是理论上的限制还是编译器的限制?
在 Haskell 中,它们受到相同的对待。
AFAIK,Haskell 将它们分配在堆上。这相当于Box<dyn Fn()>Rust 中的。由于您将它们装箱,因此您知道大小将始终为2*usize(数据指针和虚函数表指针)。
默认情况下,Rust 不会对闭包进行装箱。相反,每个闭包都会获得一个新的、不可命名的结构,其中包含所有捕获的变量。例如,以下内容:
let a: i32 = 123;
let closure = |b: i32| -> i32 { a + b };
Run Code Online (Sandbox Code Playgroud)
翻译成类似的东西(不完全是,但并不重要):
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
}
}
Run Code Online (Sandbox Code Playgroud)
这样效率更高,本质上使得闭包零成本,但我们要付出的代价是不同的闭包在内存中的布局不同。因此,即使它们具有相同的签名,它们也不相等,因此您不能返回其中之一。
此外,即使它们碰巧具有相同的布局,您仍然无法返回不同的闭包类型,因为闭包是静态分派的。我们不依赖 vtable 来查找闭包代码,而是直接调用它。同样,这使它们的成本为零,这对 Rust 很重要,但意味着如果它们不是同一个闭包,您将无法知道要调用哪些代码。
有一种特殊情况:不捕获任何内容的闭包可以转换为函数指针。这就像一个没有数据指针的虚函数表,因为我们知道它们没有数据:
let closure = if condition {
|| {} as fn()
} else {
|| {} as fn()
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
148 次 |
| 最近记录: |