我有这个签名,我想在一个特征中使用它来创建许多适配器(文件系统、AWS、Google Cloud等).

我正在try 创建以下Trait个,但出现以下错误:

use tokio::io::AsyncRead;

#[async_trait::async_trait]
pub trait Trait: Send + Sync {
    async fn put_file<S>(&self, filename: &str, stream: S) -> Result<()>
    where
        S: AsyncRead + Send;
}

pub struct Client {
    location: String,
}

#[async_trait::async_trait]
impl Trait for Client {
    async fn put_file<S>(&self, filename: &str, stream: S) -> Result<()>
    where
        S: AsyncRead + Send,
    {
        futures::pin_mut!(stream);

        let path = Path::new(&self.location).join(filename);

        let mut file = BufWriter::new(File::create(path).await?);

        tokio::io::copy(&mut stream, &mut file).await?;

        Ok(())
    }
}
error[E0038]: the trait `Trait` cannot be made into an object
   |
23 |     pub client: Arc<dyn Trait>,
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Trait` 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>
   |
5  | pub trait Trait: Send + Sync {
   |           ----- this trait cannot be made into an object...
6  |     async fn put_file<S>(&self, filename: &str, stream: S) -> Result<()>
   |              ^^^^^^^^ ...because method `put_file` has generic type parameters
   = help: consider moving `put_file` to another trait

为什么?

推荐答案

如果您阅读您的错误消息,它会同时提到它是

...因为方法put_file具有泛型类型参数

以及你在哪里可以找到关于object safety的更多信息

您可以不创建特征对象,而是:

struct YourStructThatContainsTrait<T: Trait> {
    pub client: Arc<T>,
}

或者全程采用动态调度:

async fn put_file(&self, filename: &str, stream: Box<dyn AsyncRead + Unpin + Send>) -> Result<()>;

Rust相关问答推荐

新创建的变量的绑定生存期

像这样的铁 rust 图案除了‘选项’之外,还有其他 Select 吗?

在Rust中,Box:ed struct 与普通 struct 在删除顺序上有区别吗?

什么时候使用FuturesOrdered?

Rust从关联函数启动线程

如何处理闭包中的生命周期以及作为参数和返回类型的闭包?

`use` 和 `crate` 关键字在 Rust 项目中效果不佳

注释闭包参数强调使用高阶排定特征界限

如何将 C++ 程序链接到 Rust 程序,然后将该 Rust 程序链接回 C++ 程序? (cpp -> rust -> cpp)

使用 lalrpop 在 rust 中解析由 " 引用的字符串

std::vector::shrink_to_fit 如何在 Rust 中工作?

如何刷新 TcpStream

在 Rust 中使用 `SecTrustSettingsSetTrustSettings` 绑定导致 `errSecInternalComponent`

将 Futures 的生命周期特征绑定到 fn 参数

为什么 Rust 编译器在移动不可变值时执行复制?

Rust HRTB 是相同的,但编译器说一种类型比另一种更通用

Cargo:如何将整个目录或文件包含在功能标志中?

在 Rust 中枚举字符串的最佳方式? (字符()与 as_bytes())

TinyVec 如何与 Vec 大小相同?

如何重写这个通用参数?