这段奇怪的代码会从
do_the_thing()
发出错误,表示 T
的寿命不够长:
use std::future::Future;
trait Connection: Send {
type ExecFut<'a>: Future<Output = ()> + Send
where
Self: 'a;
fn transaction<F>(&mut self, _f: F)
where
F: for<'a> FnOnce(&'a mut Self) -> Box<dyn Future<Output = ()> + Send + 'a> + Send,
{
unimplemented!()
}
fn execute<'a>(&'a mut self) -> Self::ExecFut<'a> {
unimplemented!()
}
}
fn do_the_thing<T: Connection>(connection: &mut T) {
connection.transaction(|conn| {
Box::new(async move {
conn.execute().await;
})
});
}
error[E0310]: the parameter type `T` may not live long enough
--> src/main.rs:22:9
|
22 | / Box::new(async move {
23 | | conn.execute().await;
24 | | })
| |__________^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
20 | fn do_the_thing<T: Connection + 'static>(connection: &mut T) {
| +++++++++
在游乐场看到它。
据我所知,不应该存在需要
'static
的隐含界限。几乎所有事物都受到 'a
的限制,并且 T
中的任何生命周期都应该总是比它长。虽然显然我可能缺少一些东西。
我还发现了一些没有帮助的“解决方案”:
'static
是不合理的。它可以解决,但我想使用具有非 Connection
生命周期的真正 'static
。Send
上的 dyn Future
绑定可以使其通过编译。这对我来说毫无意义。Connection
的 'static
,它也会编译,这似乎与编译器错误相矛盾。以上并非真实代码;最初的动机源于使用 diesel-async
板条箱中的
AsyncConnection
和类似的代码结构。但是,我希望它能够代表核心问题,并且通过了解这里的问题和潜在的解决方案,可以对其进行调整。
通过进一步的修补和研究,我发现了这个问题 - GAT:决定是否对
where Self: 'a
有默认值 - 关于 where
上的 type ExecFut<'a>
子句。从该问题中的评论来看,其他人似乎因执行此限制而遇到了类似的错误。
该问题提供了一种解决方法,即将您的特征分为两部分 - 一个用于关联类型,另一个用于方法,以便可以省略
where Self: 'a
子句。在我的示例中这样做可以使其编译:
trait Connection: Send {
type ExecFut<'a>: Future<Output = ()> + Send;
}
trait ConnectionExt: Connection {
fn transaction<F>(&mut self, _f: F)
where
F: for<'a> FnOnce(&'a mut Self) -> Box<dyn Future<Output = ()> + Send + 'a> + Send,
{
unimplemented!()
}
fn execute<'a>(&'a mut self) -> Self::ExecFut<'a> {
unimplemented!()
}
}
impl Connection for &'_ i32 {
type ExecFut<'a> = std::future::Ready<()>;
}
impl<C> ConnectionExt for C where C: Connection {}
fn do_the_thing<T: Connection>(connection: &mut T) {
connection.transaction(|conn| {
Box::new(async move {
conn.execute().await;
})
});
}
我仍然需要看看这在柴油机异步情况下是否是一个可用的解决方案。
作为旁注,还有另一个相关问题 - GAT、异步和发送边界问题 - 描述了上述边界和
Send
之间的奇怪交互,这 可能 解释了为什么要删除 Send
bound 导致代码片段编译。还是很奇怪。