如何将代码重写为新的未装箱闭包
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);
}
谁能帮我用新的未装箱的闭包重写这段代码:
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);
}