kmd*_*eko 6 lifetime rust async-await generic-associated-types
这段奇怪的代码会发出一个错误,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;
})
});
}
Run Code Online (Sandbox Code Playgroud)
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;
})
});
}
Run Code Online (Sandbox Code Playgroud)
在操场上看到它。
据我所知,不应该'static需要任何隐含的界限。几乎所有事物都受到限制,并且无论如何,'a任何生命周期都应该比它更长寿。T尽管显然我可能缺少一些东西。
我还发现了一些没有帮助的“解决方案”:
'static是不合理的。它可以解决,但我想使用Connection具有非生命周期的 real 。'staticSend上的绑定dyn Future使其通过编译。这对我来说毫无意义。Connection不是'static它也可以编译,这似乎与编译器错误相矛盾。以上并非真实代码;最初的动机源于使用AsyncConnectiondiesel -async crate和类似的代码结构。然而,我希望它能够代表核心问题,并且通过理解这里的问题和潜在的解决方案,可以对其进行调整。
通过进一步的修补和研究,我发现了这个问题 - GATs: Decide if to have defaults forwhere Self: 'a - 关于 的where条款type ExecFut<'a>。从该问题的评论来看,似乎其他人在执行此限制时也遇到了类似的错误。
该问题提供了一种解决方法,即将您的特征分为两部分 - 一个用于关联类型,另一个用于方法,以便where Self: 'a可以省略该子句:
这破坏了我的代码。解决方法?
首先,如果任何代码无法添加所需的边界,我们确实需要反馈。其次,解决方法是将 GAT 转变为超级特征。使用上面的示例,我们的新代码将如下所示:
Run Code Online (Sandbox Code Playgroud)trait IterableSuper { type Item<'x>; } trait Iterable: IterableSuper { fn iter<'a>(&'a self) -> Self::Item<'a>; }
在我的示例中执行此操作可以使其编译,但在我的目标用例中它确实开始变得混乱。
我见过提到的另一个解决方法是引入一个虚拟函数,该函数使用关联的类型但不与self. 这也允许您省略该where Self: 'a子句,因此代码可以编译:
trait Connection: Send {
type ExecFut<'a>: Future<Output = ()> + Send;
// ^^^^^^^^^^^^^^^^ does not need `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 _disable_lint_for_exec_fut<'a>(_: Self::ExecFut<'a>) { }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dummy function
}
Run Code Online (Sandbox Code Playgroud)
作为旁注,还有另一个链接的问题 - GAT、异步和发送边界的问题- 描述了如上所述的边界之间的奇怪交互,Send这可以解释为什么删除Send边界会导致代码片段编译。还是很奇怪。
| 归档时间: |
|
| 查看次数: |
79 次 |
| 最近记录: |