如何将代码重写为新的未装箱闭包 [英] How to rewrite code to new unboxed closures

查看:54
本文介绍了如何将代码重写为新的未装箱闭包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Can somebody help me to rewrite this piece of code with new unboxed closures:

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

    builder
}

我试着这样写,但我遇到了一生的错误:

I tried to write like this, but I got a lifetime error:

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

我需要指定什么生命周期?沙盒中的简化示例.

What lifetime I need to specify? Simplified example in the sandbox.

推荐答案

这需要 更高等级的特征界限,特别是更高等级的生命周期.完整的无糖语法将是 F: for<'a>FnOnce<(&'a mut Builder,), ()>.

This requires higher rank trait bounds, specifically, higher rank lifetimes. The full unsugared syntax would be F: for<'a> FnOnce<(&'a mut Builder,), ()>.

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

Using a lifetime on the function can't work, e.g. if we had

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,因此编译器认为替换 中的一个是合法的>&mut builder.

This says that build works with whatever lifetime the caller wishes (e.g. they could chose 'b == 'static), but this is invalid, because there is a specific concrete lifetime that needs to be the used: the lifetime of the &mut builder inside the function. Using F: for<'a> ... in a bound says that F works with any lifetime 'a, so the compiler sees that it is legal to substitute in the one of &mut builder.

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

As I hinted above, that's the really ugly unsugared syntax. There's two successive ways this can be made much nicer. Firstly, the canonical way to use the closure traits is the () sugar: for<'a> FnOnce(&'a mut Builder) -> (), or, like with the rest of Rust, the -> () can be dropped: for<'a> FnOnce(&'a mut Builder). (NB. this is just sugar for FnOnce<...>, but only the sugared syntax will be stabilised for interacting with these traits at 1.0.)

然后,paren 语法有一点额外的规则:它会自动插入类似于 for<'a> 的生命周期(具体来说,它经历了 lifetime elision 将任何插入的生命周期放入特征的 for 中),所以只需F: FnOnce(&mut Builder) 等价于 F: for<'a>FnOnce(&'a mut Builder),这是推荐的版本.

Then, the paren syntax has a little extra rule: it automatically inserts lifetimes that act like for<'a> (specifically, it undergoes lifetime elision with any inserted lifetime placed into a for on the trait), so just F: FnOnce(&mut Builder) is equivalent to F: for<'a> FnOnce(&'a mut Builder), and it's the recommended version.

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

Applying these fixes to your playpen example:

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);
}

围栏

这篇关于如何将代码重写为新的未装箱闭包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆