我想将基于async_trait
的代码迁移到新的async traits feature(将在Rust 1.75中发布)。我现有的遗留代码:
#[async_trait::async_trait]
pub trait SourceOld: Send {
async fn get_async(&self) -> Result<String, ()>;
fn clone(&self) -> Box<dyn SourceOld>;
}
pub fn process_old_sources(_sources: Vec<Box<dyn SourceOld>>) {
todo!()
}
把它改写成...
pub trait SourceNew: Send {
async fn get_async(&self) -> Result<String, ()>;
fn clone(&self) -> Box<dyn SourceNew>;
}
pub fn process_new_sources(_sources: Vec<Box<dyn SourceNew>>) {
todo!()
}
编译它会对两种Box<dyn SourceNew>
用法产生此错误。
error[E0038]: the trait `SourceNew` cannot be made into an object
--> src/lib.rs:10:28
|
10 | fn clone(&self) -> Box<dyn SourceNew>;
| ^^^^^^^^^^^^^ `SourceNew` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> src/lib.rs:9:14
|
7 | pub trait SourceNew: Send {
| --------- this trait cannot be made into an object...
8 | // fn get_async(&self) -> impl std::future::Future<Output = Result<String, ()>> + Send;
9 | async fn get_async(&self) -> Result<String, ()>;
| ^^^^^^^^^ ...because method `get_async` is `async`
= help: consider moving `get_async` to another trait
nightly编译器也建议用这个替换get_async
,但这似乎没问题。
fn get_async(&self) -> impl std::future::Future<Output = Result<String, ()>> + Send;
1条答案
按热度按时间rjjhvcjd1#
async_fn_in_trait
还不是async-trait
的完全替代品,也不是每个人都可以使用它。稳定的特性是MVP,将来应该扩展。有两个特征不稳定:动态调度,并在呼叫现场约束未来。
动态分派意味着允许使用包含
async fn
的trait或将impl Trait
作为dyn Trait
返回的方法。在调用点约束future意味着,假设你有async fn foo()
,能够为一个接受impl ThatTrait
的方法指定foo()
返回的future是Send
(例如)。同样,限制impl Trait
返回方法的返回类型的能力也不稳定。这些功能目前还不稳定,因为它们很大很复杂,而且在设计上有问题。我将试着简短地解释为什么。
动态分派根本没有实现(截至撰写本文时),因为还不清楚如何实现它。traits中的
async fn
s被去糖化为具有返回future的关联类型的函数,但是关联类型对于不同的实现可以是不同的,并且在堆栈上具有不同的大小,所以就像常规的关联类型一样,我们不能在dyn Trait
上调用这个方法。async-trait
通过将返回的future装箱来解决这个问题。然而,对于语言解决方案,我们希望避免在静态分派的情况下装箱。所以这需要在非装箱方法和装箱方法之间进行某种转换。目前还不清楚这种转换应该如何实现,特别是因为我们不想要隐式分配。Niko Matsakis has wrote a series on this subject titled "Dyn async traits"。约束未来是以一种小的形式实现的(称为RTN,返回类型表示法),但不清楚这是我们想要结束的。目前还不清楚什么语法最适合约束它,因为这是一个新事物(在Rust中没有其他地方可以通用地引用方法的返回类型)以及语义是什么。Niko wrote a series about that too。
总而言之,traits中的functionfn适合那些不需要动态分派和不需要约束未来的人(例如,嵌入式的人,或者有时也在其他地方的人)。其他人应该继续使用
async-trait
,并等待更多的稳定。