我正在使用锈0.8。
为什么我能这样做:
fn add(num: ~int) -> ~fn(int) -> int { |x|
*num + x
}
但不是这样:
fn outer(num: ~int) -> ~fn(int) -> int { |x|
*inner(num) + x
}
fn inner(num: ~int) -> ~int {
num
}
第二个失败了,“错误:无法移出堆闭包中捕获的外部变量”。什么使调用函数特殊?
是否担心内部函数可能会对静态分析无法捕获的盒装函数执行某些操作?
答案 0 :(得分:3)
问题是可以两次调用闭包。在第一次运行时,捕获的变量num
被移动到inner
,即移出闭包的环境。然后,在第二次调用时,num
所在的位置现在无效(因为它被移出),这会破坏内存安全。
更详细地说,可以将闭包视为(近似)
struct Closure { // stores all the captured variables
num: ~int
}
impl Closure {
fn call(&self, x: int) -> int {
// valid:
*self.num + x
// invalid:
// *inner(self.num) + x
}
}
希望这更清楚:在无效的一个中,有人试图将self.num
从借用的指针后面移到inner
调用之后(之后它完全与{{1}断开连接}}}。如果这是可能的,则num
将处于无效状态,因为例如self
上的析构函数可能已被调用,从而释放内存(违反内存安全性)。
这个的一个解决方案是“一次性函数”,它们被实现但隐藏在编译器标志后面,因为它们可能被删除而有利于(最基本的)调整上面self.num
的类型是call
,即调用闭包移动fn call(self, x: int)
,这意味着您可以移出环境(因为self
然后拥有call
及其字段)并且还意味着该函数静态保证仅被调用一次*。
*如果关闭的环境不会移动所有权,则不严格为真,例如如果是self
。