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

时间:2015-01-07 08:35:18

标签: rust rust-obsolete

有人可以帮我用新的未装箱的闭包来重写这段代码:

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

1 个答案:

答案 0 :(得分:12)

这需要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中替换()是合法的。

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

然后,paren语法有一些额外的规则:它会自动插入像for一样的生命周期(具体来说,它会经历lifetime elision,其中任何插入的生命周期都放在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); } ,这是推荐的版本。

将这些修补程序应用于您的游戏围栏示例:

{{1}}

playpen