有人可以帮我用新的未装箱的闭包来重写这段代码:
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
答案 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}}