9

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

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,), ()> {
                                                                                   ^~~~~~~~~~~~

我需要指定什么寿命?沙箱中的简化示例

4

1 回答 1

11

这需要更高等级的特征界限,特别是更高等级的生命周期。完整的无糖语法是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> ...in a bound 表示F适​​用于任何生命周期'a,因此编译器认为在 of 中替换是合法的&mut builder

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

然后,paren 语法有一点额外的规则:它会自动插入行为类似的生命周期for<'a>(具体来说,它会经历生命周期省略,任何插入的生命周期都放在fortrait 上),所以 justF: 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);
}

围栏

于 2015-01-07T08:48:01.383 回答