考虑下面这个最小的例子:
type Task<'a> = Box<dyn std::future::Future<Output = ()> + 'a>;
type Context<'s> = &'s str;
trait MyTrait {
fn compute<'a>(&'a self, ctx: Context<'a>) -> Task<'a>
where
Self: 'a;
}
impl<F: for<'b> Fn(Context<'b>) -> Task<'b>> MyTrait for F {
fn compute<'a>(&'a self, ctx: Context<'a>) -> Task<'a>
where
Self: 'a,
{
(self)(ctx)
}
}
fn bla<'op>(input: &'op usize) -> impl MyTrait + 'op {
let v: Box<dyn for<'b> Fn(Context<'b>) -> Task<'b> + 'op> = Box::new(move |ctx| {
Box::new(async move {
println!("{}", &ctx[*input..]);
()
})
});
v
}
编译器生成的错误消息为:
error: lifetime may not live long enough
--> src/main.rs:22:9
|
20 | fn bla<'op>(input: &'op usize) -> impl MyTrait + 'op {
| --- lifetime `'op` defined here
21 | let v: Box<dyn for<'b> Fn(Context<'b>) -> Task<'b> + 'op> = Box::new(move |ctx| {
22 | / Box::new(async move {
23 | | println!("{}", &ctx[*input..]);
24 | | ()
25 | | })
| |__________^ returning this value requires that `'op` must outlive `'static`
我不明白为什么'op
一定要比'static
长,返回的Task
的生存期受'b
的限制,而'b
又比装箱闭包的Self
短,因此也比'op
短。
我还尝试更明确地对trait对象的生命周期建模,但从下面的代码中得到了相同的错误消息:
type Task<'a> = Box<dyn std::future::Future<Output = ()> + 'a>;
type Context<'s> = &'s str;
trait MyTrait<'l> {
fn compute<'a>(&'l self, ctx: Context<'a>) -> Task<'l>
where
'l: 'a;
}
impl<'c, F: 'c + for<'b> Fn(Context<'b>) -> Task<'b>> MyTrait<'c> for F {
fn compute<'a>(&'c self, ctx: Context<'a>) -> Task<'c>
where
'c: 'a,
{
(self)(ctx)
}
}
fn bla<'op>(input: &'op usize) -> impl MyTrait<'op> + 'op {
let v: Box<dyn for<'b> Fn(Context<'b>) -> Task<'b> + 'op> = Box::new(move |ctx| {
Box::new(async move {
println!("{}", &ctx[*input..]);
()
})
});
v
}
编辑:我猜另一种更开放的问这个问题的方式会是:如何用一个外部生命周期来约束一个HRTB的生命周期?
1条答案
按热度按时间6ss1mwsb1#
我不明白为什么
'op
一定要比'static
长,返回的Task
的生存期受'b
的限制,而'b
又比装箱闭包的Self
短,因此也比'op
短。谁说的?编译器唯一知道的是它必须在 * any * lifetime(HRTB)内为真。* any * lifetime包括
'static
,因此编译器需要'op: 'b
,这意味着'op: 'static
。