移动闭包的特征?

Trait bound for move-closures?

有没有办法在 Rust 中使用特征绑定来区分 move 闭包和非 move 闭包?

对于上下文,我在我的程序中使用盒装闭包(Box + dyn Fn 特征),所以我需要担心生命周期,因为 IIUC 这些闭包可能引用堆栈。

我想知道我是否可以限制为盒装 move-闭包,这样(希望)我可以避免处理生命周期,因为在这种情况下这些很快就会变得混乱。

或者是否有其他更好、更惯用的方法来达到相同的结果?

Is there a way to distinguish move closures from non-move closures using a trait bound in Rust?

“移动”在这里是一个转移注意力的问题。您可以在闭包 中通过引用借用变量,您可以 将引用移动 到闭包中,它们等价地相同。示例:

fn takes_closure<'a>(_closure: &'a dyn Fn() -> &'a i32) {}

fn main() {
    let value = 123;
    let value_ref = &value;
    
    // captures value by borrowing it by reference
    takes_closure(&|| &value);
    
    // captures value_ref by moving it
    takes_closure(& move || value_ref);
    
    // what's the difference between the above 2 cases?
    // answer: there isn't any
}

I'm using boxed closures in my program so I need to worry about lifetimes since IIUC these closures may reference the stack.

不,默认情况下盒装闭包得到一个隐式 'static 绑定。除非您明确设置自己的生命周期界限,否则您不能在盒装闭包中借用堆栈变量。

From Default trait object lifetimes in The Rust Reference:

If the trait has no lifetime bounds, then the lifetime is inferred in expressions and is 'static outside of expressions.

例如,仅此函数签名就可以保证返回的闭包不会捕获任何非'static 外部引用或变量:

fn returns_boxed_closure() -> Box<dyn Fn()>;
// full desugared return type: Box<dyn Fn() + 'static>

如上所述,如果您希望盒装闭包不受 'static 生命周期的限制,您必须明确地对其进行注释。这是一个例子:

fn returns_boxed_closure<'a, T>(reference: &'a T) -> Box<dyn Fn() + 'a> {
    Box::new(move || drop(reference))
}

上面的例子特别好,因为它表明即使你使用move关键字你仍然可以用它来创建一个盒装的非'static生命周期的闭包。

总之,简而言之:您不必做任何特别的事情,盒装闭包会默认获得隐式 'static 绑定,并按您希望的方式工作,即您不必担心关于生命周期。