![](/img/trans.png)
[英]Rust showing expected trait object `dyn Future`, found opaque type when passing function as a param
[英]Rust Trait warning: method references the `Self` type in its `where` clause
我们正在尝试创建一个指向特征 object 的指针,并收到一条警告,指出该特征不能变成 object。
use async_trait::async_trait;
use std::sync::{Arc, Weak};
fn main() {
println!("Hello, world!");
}
pub type MyTraitPtr = Arc<dyn MyTrait>;
#[async_trait]
pub trait MyTrait {
async fn foo(&self) {}
}
pub struct Parent {
child: MyTraitPtr,
}
这会产生以下警告:
warning: the trait `MyTrait` cannot be made into an object
--> src/main.rs:14:14
|
14 | async fn foo(&self) {}
| ^^^
|
= note: `#[warn(where_clauses_object_safety)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443>
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/main.rs:14:14
|
13 | pub trait MyTrait {
| ------- this trait cannot be made into an object...
14 | async fn foo(&self) {}
| ^^^ ...because method `foo` references the `Self` type in its `where` clause
= help: consider moving `foo` to another trait
完整代码: https://github.com/lunar-mining/trait_ptr
更新:如果我们将 Sync 添加到 Trait 定义中,那么它会编译,如下所示:
use std::sync::{Arc, Weak};
fn main() {
println!("Hello, world!");
}
pub type MyTraitPtr = Arc<dyn MyTrait>;
#[async_trait]
pub trait MyTrait: Sync {
async fn foo(&self) {}
}
pub struct Parent {
child: MyTraitPtr,
}
但是,如果特征的方法采用对 Self 的 Arc 引用,则它不会编译:
use async_trait::async_trait;
use std::sync::{Arc, Weak};
fn main() {
println!("Hello, world!");
}
pub type MyTraitPtr = Arc<dyn MyTrait>;
#[async_trait]
pub trait MyTrait: Sync {
async fn foo(self: Arc<Self>) {}
}
pub struct Parent {
child: MyTraitPtr,
}
您可以通过将实现移出特征来实现它:
use async_trait::async_trait;
use std::sync::{Arc, Weak};
pub type MyTraitPtr = Arc<dyn MyTrait>;
#[async_trait]
pub trait MyTrait {
async fn foo(&self);
}
impl dyn MyTrait {
async fn foo(&self) { }
}
pub struct Parent {
child: MyTraitPtr,
}
您也可以直接将其实现到 Arc:
pub type MyTraitPtr = Arc<dyn MyTrait>;
#[async_trait]
pub trait MyTrait: Sync + Send {
async fn foo(&self);
}
#[async_trait]
impl MyTrait for MyTraitPtr {
async fn foo(&self) { }
}
pub struct Parent {
child: MyTraitPtr,
}
动态特性
具有异步方法的特征可以用作特征对象,只要它们满足 dyn 的通常要求——没有带有类型参数的方法、没有按值的自我、没有关联类型等。
...
一个问题在于提供异步方法默认实现的特征。 为了让默认实现产生一个发送的未来,async_trait 宏必须发出一个 Self 的边界:在采用
&self
的特征方法上Self: Sync
和一个绑定的Self: Send
。 前者的示例在上面解释部分的扩展代码中可见。如果您使用具有默认实现的异步方法创建一个特征,除了该特征不能用作特征 object 之外,一切都会正常工作。创建
&dyn Trait
类型的值将产生如下所示的错误:error: the trait `Test` cannot be made into an object --> src/main.rs:8:5 | 8 | async fn cannot_dyn(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
对于需要 object 安全并且需要对某些异步方法具有默认实现的特征,有两种解决方案。 您可以将 Send 和/或 Sync 添加为超特征(如果有默认实现的
&mut self
方法则发送,如果有默认实现的&self
方法则同步)以约束特征的所有实现者,以便默认实现适用于它们:#[async_trait] pub trait ObjectSafe: Sync { // added supertrait async fn can_dyn(&self) {} } let object = &value as &dyn ObjectSafe;
或者你可以通过将它们与
Self: Sized
绑定来从你的特征 object 中删除有问题的方法:#[async_trait] pub trait ObjectSafe { async fn cannot_dyn(&self) where Self: Sized {} // presumably other methods } let object = &value as &dyn ObjectSafe;
Arc
在这方面被认为与可变引用相同,并且需要Send
绑定。 另请参阅我发布到async-trait
的错误报告。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.