特性无法转换为对象

49

我有如下代码:

extern crate futures; // 0.1.24

use futures::Future;
use std::io;

struct Context;

pub trait MyTrait {
    fn receive(context: Context) -> Future<Item = (), Error = io::Error>;
}

pub struct MyStruct {
    my_trait: MyTrait,
}

当我尝试编译它时,我收到错误信息:

error[E0038]: the trait `MyTrait` cannot be made into an object
  --> src/lib.rs:13:5
   |
13 |     my_trait: MyTrait,
   |     ^^^^^^^^^^^^^^^^^ the trait `MyTrait` cannot be made into an object
   |
   = note: method `receive` has no receiver

我想我知道它为什么会发生,但是我该如何从结构体中引用这个特征?这可能吗?也许有其他实现相同行为的方法?

3个回答

43
你可以在你的结构体中添加一个类型参数,就像Zernike的回答中所示,或者使用trait对象。
对于性能而言,使用类型参数更好,因为每个T值都会创建一个专门的结构体副本,这允许进行静态分派。Trait对象使用动态分派,因此它允许你在运行时交换具体类型。
使用trait对象的方法如下:
pub struct MyStruct<'a> {
    my_trait: &'a dyn MyTrait,
}

或者这样:
pub struct MyStruct {
    my_trait: Box<dyn MyTrait>,
}

但在你的情况下,MyStruct 不能被转变为对象,因为 receive 是一个静态方法。你需要将它改为采用 &self&mut self 作为其第一个参数才能使其工作。 还有其他限制


17

4
我不喜欢这种变体,因为这样我以后就不能用另一个实例替换 T。 - Alexander

-1

还有第四个选项可用,但这将使您的结构变得不定长,即您将无法创建此结构的实例。

pub trait MyTrait {}

pub struct MyStruct {
    my_trait: dyn MyTrait + 'static,
}

这意味着MyStruct是一种无大小的类型,您不能直接创建此类类型的实例。由于Rust目前没有一种直接在堆栈上分配结构体的方法,我不知道是否可以创建此类类型的实例。但是,它可以编译

1
你如何在Rust中实际使用动态大小类型? - Shepmaster
@Shepmaster 我知道如何使用无大小类型。但我找不到一种实例化这个特定类型的方法。我知道如何处理像 struct Foo(str) 这样的类型,但我找不到处理这个类型的方法。 - Hauleth
1
我同意目前无法做到。该链接是为了当某人在X个月后浏览此答案时,可以更轻松地使用DSTs。该问答将随着新信息的更新而更新;但本问题的更新可能性较小。 - Shepmaster
它不再编译: 警告:这在当前版本(Rust 2015)中被接受,但在 Rust 2021 中是一个严格的错误! 注意:有关更多信息,请参见https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html 帮助:使用 dyn - Code4R7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接