如何将代码重写为新的未装箱闭包

How to rewrite code to new unboxed closures

谁能帮我用新的未装箱的闭包重写这段代码:

struct Builder;
pub fn build(rules: |params: &mut Builder|) -> Builder {
    let mut builder = Builder::new();
    rules(&mut builder);

    builder
}

我试着这样写,但是我得到了一个终生错误:

pub fn build<F>(rules: F) -> Builder where F: FnOnce<(&mut Builder,), ()> {
    let mut builder = Builder::new();
    rules(&mut builder);

    builder
}

valico/src/builder.rs:48:59: 48:71 error: missing lifetime specifier [E0106]
valico/src/builder.rs:48     pub fn build<F>(rules: F) -> Builder where F: FnOnce<(&mut Builder,), ()> {
                                                                                   ^~~~~~~~~~~~

我需要指定多长时间? Simplified example in the sandbox.

这需要 higher rank trait bounds,特别是更高等级的寿命。完整的无糖语法为 F: for<'a> FnOnce<(&'a mut Builder,), ()>.

在函数上使用生命周期是行不通的,例如如果我们有

pub fn build<'b, F>(rules: F) -> Builder where F: FnOnce<(&'b mut Builder,), ()>

这表示 build 可以在调用者希望的任何生命周期内工作(例如,他们可以选择 'b == 'static),但这是无效的,因为有一个特定的具体需要使用的生命周期:函数内部&mut builder的生命周期。在绑定中使用 F: for<'a> ... 表示 F 适用于任何生命周期 'a,因此编译器认为替换为 &mut builder.[=33= 之一是合法的]

正如我在上面暗示的那样,这是非常丑陋的未加糖语法。有两种连续的方法可以使它变得更好。首先,使用闭包特征的规范方法是 () 糖:for<'a> FnOnce(&'a mut Builder) -> (),或者,与 Rust 的其余部分一样,可以删除 -> ()for<'a> FnOnce(&'a mut Builder)。 (注意。这只是 FnOnce<...> 的糖分,但在 1.0 中只有糖分语法会稳定以与这些特征交互。)

然后,paren 语法有一点额外的规则:它会自动插入行为类似于 for<'a> 的生命周期(具体来说,它经历 lifetime elision 并将任何插入的生命周期放入 for在 trait 上),所以 F: FnOnce(&mut Builder) 等同于 F: for<'a> FnOnce(&'a mut Builder),这是推荐的版本。

将这些修复应用到您的围栏示例中:

pub fn initialize_with_closure<F>(rules: F) -> uint where F: FnOnce(&mut uint) {
    let mut i = 0;
    rules(&mut i);

    i
}

// equivalently
pub fn initialize_with_closure_explicit<F>(rules: F) -> uint where F: for<'a> FnOnce(&'a mut uint) -> () {
    let mut i = 0;
    rules(&mut i);

    i
}

pub fn main() {
    initialize_with_closure(|i: &mut uint| *i = *i + 20);
    initialize_with_closure_explicit(|i: &mut uint| *i = *i + 20);
}

playpen