特征不能成为一个对象

时间:2017-07-15 10:09:34

标签: generics rust traits dynamic-dispatch trait-objects

我有以下代码:

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 个答案:

答案 0 :(得分:14)

您可以在结构中添加类型参数,如Zernike's answer中所示,或使用特征对象。

使用type参数对性能更好,因为T的每个值都将创建结构的专用副本,允许静态分派。特征对象使用动态分派,因此它允许您在运行时交换具体类型。

特质对象方法如下所示:

pub struct MyStruct<'a> {
    my_trait: &'a dyn MyTrait,
}

或者这个:

pub struct MyStruct {
    my_trait: Box<dyn MyTrait>,
}

但是,在您的情况下,MyStruct无法成为对象,因为receive是静态方法。您需要将其更改为&self&mut self作为其第一个参数。还有other restrictions

答案 1 :(得分:4)

pub struct MyStruct<T>
where
    T: MyTrait,
{
    my_trait: T,
}

pub struct MyStruct<T: MyTrait> {
    my_trait: T,
}

https://doc.rust-lang.org/book/second-edition/ch10-02-traits.html#trait-bounds

答案 2 :(得分:0)

还有第四个选项,但这将使您的结构没有大小,也就是您将无法创建该结构的实例。

getForTimestamps(timestamps: string[] = []) {
    const observableBatch = [];

    timestamps.forEach((timestamp) => {
      observableBatch.push(this.restangular.all('myapi').customGET('', {timestamp})
        .pipe(
          catchError((err) => observableThrowError(err) ),
          map((r) => {
            return {[timestamp]: r}
          })));
    })
    return observableBatch.length > 0 ? observableForkJoin(observableBatch) : observableOf([]);
}

这意味着pub trait MyTrait {} pub struct MyStruct { my_trait: dyn MyTrait + 'static, } 是一个无大小的类型,您不能创建该类型的直接实例。由于Rust目前尚无法直接在堆栈上分配结构,因此我不知道是否可以创建这种类型的实例。但是,it compiles