更高排名的特质限制和盒装封闭寿命问题

Vae*_*den 8 lifetime rust

我正在尝试编写一个函数返回一个盒装闭包,它可以处理对任何生命周期的类型的引用.在编写特定实例时,一切正常.但是在编写通用版本时,我会遇到终身问题.

struct Parameter<'a> {
    s: &'a str,
}

fn main() {
    let closure = generate_closure_gen();
    let string = String::from("Hello World!");
    let parameter = Parameter { s: &string }; // Error: string does not live long enough
    closure(&parameter);
}

// This one works fine
// Desugared version for Box<Fn(&Parameter)>
fn generate_closure() -> Box<for <'a, 'r> Fn(&'r Parameter<'a>)> {
    Box::new(|c: &Parameter| {})
}

// This one gives lifetime errors
fn generate_closure_gen<C>() -> Box<Fn(&C)> {
    Box::new(|c: &C| {})
}
Run Code Online (Sandbox Code Playgroud)

我不明白为什么闭包需要类型参数比它更长寿(没有存储或任何东西......).它适用于具有HRTB的非通用版本,它只是觉得应该可以使它与泛型版本一起使用.
此外,如果我尝试使用通用版本编写特定版本,我会收到类型错误

// Desugared version for Box<Fn(&Parameter)>
fn generate_closure_2() -> Box<for <'a, 'r> Fn(&'r Parameter<'a>)> {
    generate_closure_gen()
}

src/main.rs:22:5: 22:27 error: mismatched types:
 expected `Box<for<'r, 'r> core::ops::Fn(&'r Parameter<'r>) + 'static>`,
    found `Box<for<'r> core::ops::Fn(&'r _) + 'static>`
(expected concrete lifetime,
    found bound lifetime parameter ) [E0308]
src/main.rs:22     generate_closure_gen()
                   ^~~~~~~~~~~~~~~~~~~~~~
src/main.rs:22:5: 22:27 help: run `rustc --explain E0308` to see a detailed explanation
Run Code Online (Sandbox Code Playgroud)

有关如何使这项工作的任何想法?

(围栏链接)

Fra*_*gné 7

类型参数具有生命周期约束.生命周期限制是所有实现者生命周期参数中最短的.你省略了它generate_closure_gen,所以编译器推断它,但是如果我们明确写出来,函数定义将如下所示:

fn generate_closure_gen<'a, C: 'a>() -> Box<Fn(&C)> {
    Box::new(|c: &C| {})
}
Run Code Online (Sandbox Code Playgroud)

但是,进行此更改并不能解决我们的问题.

要理解为什么,我们需要弄清楚C推断出来的是什么.用a调用闭包,&'y Parameter<'x>闭包接受for<'b> &'b C,C同样Parameter<'x>.Parameter<'x>有一个生命周期参数,它会对生命周期的约束产生影响C.

泛型函数中的生命周期参数必须替换为函数调用之前的生命周期.在这种情况下,这意味着C我们传递给闭包的任何生命周期必须在调用之前有效generate_closure_gen.那是因为C受限于特定的生命周期,而不是任何生命周期; 即,当CParameter<'x>时,'x必须提前已知的; 'x每次调用闭包时我们都不能有不同的东西.换句话说,你想拥有的是这样的:

fn generate_closure_gen<C: for<'a> 'a>() -> Box<Fn(&C)> {
    Box::new(|c| {})
}
Run Code Online (Sandbox Code Playgroud)

但不幸的是,这与Rust 1.7不合法.