【问题标题】:Trait bound for move-closures?移动关闭的特征?
【发布时间】:2021-03-25 12:58:03
【问题描述】:

有没有办法使用 Rust 中的 trait 绑定来区分 move 闭包和非move 闭包?

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

我想知道我是否可以只限于装箱的move-closures,以便(希望)我可以避免处理生命周期,因为在这种情况下这些很快就会变得混乱。

或者还有其他更好、更惯用的方法来达到同样的效果吗?

【问题讨论】:

  • 盒装 trait 对象已经获得了默认的 'static 绑定,来源:doc.rust-lang.org/reference/…
  • 更明确地说,特征绑定Fn(...) + 'static 指的是没有任何非静态外部引用的闭包。您不关心它们是否是使用 move 关键字创建的,或者它们是否通过任何其他方式避免了外部引用。正如@pretzelhammer 所指出的,对于Box<dyn Fn(...)>,静态生命周期限制是隐式的。如果您确实想允许非静态生命周期,则需要显式添加 + 'a 绑定。
  • @SvenMarnach 谢谢,这正是我想要的。

标签: rust closures traits lifetime borrow-checker


【解决方案1】:

有没有办法在 Rust 中使用 trait bound 来区分移动闭包和非移动闭包?

“移动”在这里是一个红鲱鱼。您可以在闭包中通过引用借用变量您可以将引用移动到闭包中,它们等效。示例:

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
}

我在我的程序中使用盒装闭包,因此我需要担心生命周期,因为 IIUC 这些闭包可能会引用堆栈。

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

From Default trait object lifetimes in The Rust Reference:

如果特征没有生命周期边界,则生命周期在表达式中推断,并且在表达式之外是 'static

例如,仅此函数签名就保证返回的闭包不会捕获任何非'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 绑定,并按照你想要的方式工作,即你不必担心生命周期。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-01
    • 1970-01-01
    相关资源
    最近更新 更多