在继承自另一个特征的特征中指定关联类型

时间:2018-12-16 18:23:49

标签: rust traits associated-types rust-actix

我开始致力于我的第一个更雄心勃勃的Rust项目,并且在我用于学习的任何资源和教程中都遇到了一些我没有遇到的问题。问题的标题捕获了抽象的问题,但是对于示例,我将使用与之战斗的具体示例。

对于我的项目,我需要与不同的第三方服务进行交互,因此我决定使用actix框架作为域中不同参与者的抽象。该框架定义了必须实现的Actor特性:

use actix::prelude::*;

struct MyActor {
    count: usize,
}

impl Actor for MyActor {
    type Context = Context<Self>;
}

我有一个自己的特征,它定义了第三方集成的接口。我们称之为Client。我希望每个客户都像演员一样。

use actix::Actor;

pub trait Client: Actor {}

在其他地方,我有一个矢量,用于存储对系统中所有活动客户端的引用。编译代码时,出现以下错误:

error[E0191]: the value of the associated type `Context` (from the trait `actix::actor::Actor`) must be specified
  --> transponder/src/transponder.rs:15:26
   |
15 |     clients: Vec<Box<Client>>
   |                      ^^^^^^ missing associated type `Context` value

我现在花了几个小时试图解决这个问题,但是没有一个起作用。

  • 我试图在特征中指定类型,但得到associated type defaults are unstable作为错误。
  • 我尝试在特征的实现中指定类型(impl Simulation),但出现associated types are not allowed in inherent impls错误。
  • 我尝试使用impl <T: Actor> Simulation for T进行了一些操作(例如,如图here所示),但没有任何效果。

我的假设是我缺少关于特征和类型的重要知识。如果有人可以帮助我解决我的问题,并指出缺少拼图的方向,我将不胜感激。我觉得我真的很想学习Rust的重要一课。

2 个答案:

答案 0 :(得分:2)

只要我从您的代码中了解到,您的主要目标就是将所有Client / Actor添加到一个集合中,并在需要时称其为常见行为。创建模仿客户端的特征,我将其命名为 ClientProxy )。

  

我有一个自己的特质,它定义了   第三方集成。我们称之为客户。我要每个客户   表现得像演员。

a: number = 2;
b: number = 1;
c: boolean = false;

// Controller with service injection
// ...

ngOnInit() {
    this.c = this.local.mathTest(this.a, this.b);
}

是这样的,实际上这意味着,如果某些结构具有Client的实现,则它也需要有Actor的实现。

考虑到我们有两个上下文 MyActor OtherActor 以及它们的Client / Actor实现。而且我们在Client中有一个行为(behavior_like_client(&self))。

pub trait Client: Actor {}

现在我们有Actor进行测试,但让我们回到问题“对象安全”,我们无法将这些Client收集到一个集合中。这就是为什么我创建pub trait Client: Actor { fn behave_like_a_client(&self); } struct MyActor { count: usize, } impl Actor for MyActor { type Context = Context<Self>; } impl Client for MyActor { fn behave_like_client(&self) { println!("I am MyActor as Client, and my count is {}", self.count); } } struct OtherActor { count: usize, } impl Actor for OtherActor { type Context = Context<Self>; } impl Client for OtherActor { fn behave_like_client(&self) { println!("I am OtherActor Client, and my count is {}", self.count); } } 来模仿ClientProxy并想在Client上实现ClientProxy的原因。为此,我们可以在泛型上实现Clients来扩展客户端:

ClientProxy

现在一切就绪,我们可以测试我们的结构:

//ClientProxy must have all behaviors in Client 
trait ClientProxy {
    fn behave_like_client(&self);
}

//This code implements ClientProxy to all Client like Objects
impl<T> ClientProxy for T
where
    T: Client,
{
    fn behave_like_client(&self) {
        self.behave_like_client();
    }
}

您可以从playground中获取完整的代码(由于缺乏依赖性,它没有在操场上运行)

答案 1 :(得分:1)

集合中所有项目的所有方法的签名必须相同,以便可以互换使用。这意味着每个项目的关联类型也必须相同。

您可以通过为Context关联类型提供具体类型来消除此错误:

Vec<Box<dyn Client<Context = Context<MyActor>>>>

但是,由于Actor的边界为Self: Sized(即it can't be made into a trait object)的约束,因此代码仍然无法使用。

相关问题