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

Rust 在从另一个特征继承的特征中指定关联类型,rust,traits,associated-types,rust-actix,Rust,Traits,Associated Types,Rust Actix,我开始着手我的第一个更雄心勃勃的锈菌项目,并与一些我在学习时使用的资源和教程中没有遇到的东西进行斗争。问题的标题抓住了抽象问题,但对于示例,我将使用我正在讨论的具体示例 对于我的项目,我需要与不同的第三方服务进行接口,我决定使用该框架作为我所在领域中不同参与者的抽象。该框架定义了必须实现的Actor特征: use actix::prelude::*; struct MyActor { count: usize, } impl Actor for MyActor { type

我开始着手我的第一个更雄心勃勃的锈菌项目,并与一些我在学习时使用的资源和教程中没有遇到的东西进行斗争。问题的标题抓住了抽象问题,但对于示例,我将使用我正在讨论的具体示例

对于我的项目,我需要与不同的第三方服务进行接口,我决定使用该框架作为我所在领域中不同参与者的抽象。该框架定义了必须实现的
Actor
特征:

use actix::prelude::*;

struct MyActor {
    count: usize,
}

impl Actor for MyActor {
    type Context = Context<Self>;
}
在其他地方,我有一个向量来存储对系统中所有活动客户端的引用。编译代码时,出现以下错误:

error[E0191]:必须指定关联类型“Context”(来自trait“actix::actor::actor`)的值
-->应答器/src/transponder.rs:15:26
|
15 |客户:Vec
|^^^^缺少关联的类型'Context'值
我花了几个小时试图解决这个问题,但没有一个有效

  • 我试图在trait中指定类型,但得到的
    关联类型默认值不稳定
    是一个错误
  • 我试图在trait的实现中指定类型(
    impl Simulation
    ),但在固有的impl中不允许使用关联的类型作为错误
  • 我尝试了一些关于T的
    impl模拟的东西(如图所示),但没有任何效果

我的假设是,我缺少一个关于性格和类型的重要知识。如果有人能帮我解决问题,并为我指出丢失的拼图块的方向,我将非常感激。我觉得这里有一个关于生锈的重要教训,我真的很想学习。

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

通过为
上下文
关联类型提供具体类型,可以消除此错误:

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

但是,代码仍然无法工作,因为
Actor
有一个
Self:Sized
的范围,这意味着,因此,您的trait也不能扩展它。

只要我从您的代码中了解到,您的主要目标是在一个集合中添加所有客户机/参与者,并在需要时调用它的常见行为。但由于对象安全性,这是不可能的,因此我们可以通过一些小技巧来实现(创建模仿客户机的trait,我将其命名为ClientProxy

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

use actix::Actor;

pub trait Client: Actor {}
pub trait Client: Actor {}
是的,它是这样工作的,实际上这意味着如果某个结构有一个客户端的实现,它也需要有Actor的实现

假设我们有两个上下文MyActorOtherActor及其客户机/参与者实现。我们在客户机中有一种行为(表现得像客户机(&self))

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

struct Container {
    clients: Vec<Box<ClientProxy>>,
}

fn main() {
    let mut container = Container {
        clients: Vec::new(),
    };
    let a = Box::new(MyActor { count: 3 });
    let b = Box::new(OtherActor { count: 4 });

    container.clients.push(a);
    container.clients.push(b);

    container
        .clients
        .iter()
        .for_each(|a| a.behave_like_client());
    //output : 
    //I am MyActor as Client, and my count is 3
    //I am OtherActor Client, and my count is 4
}
struct容器{
客户:Vec,
}
fn main(){
让mut container=container{
客户端:Vec::new(),
};
设a=Box::new(MyActor{count:3});
设b=Box::new(OtherActor{count:4});
容器。客户端。推送(a);
容器。客户端。推送(b);
容器
.客户
.国际热核实验堆(iter)
.对于每个人(| a | a.表现得像客户());
//输出:
//我是我的客户,我的数量是3
//我是另一个演员客户,我的计数是4
}

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

FYI
Client
不是对象安全的,因为
Actor
有一个
Self:Sized
绑定,所以您不能像这样使用它,不管这个问题如何。这不是关于特性继承的问题。如果只涉及一种特质,你也会遇到同样的问题<代码>啊,谢谢,那是个打字错误。但是,是的,这种处理多态性的方法是行不通的。@PeterHall谢谢你的解释。我记得读过这本书的这一部分,但直到现在它才真正合拍。我觉得actix一开始可能有点太多了。我将采用一种更简单的方法,直到我有更多的生锈经验。谢谢你的帮助!谢谢你的详细解释。这是一种有趣的方法,将来可能会派上用场。应该注意的是,只有在
Client
上的方法不依赖任何类型(如
Context
Actor
中的任何类型)时,这种方法才有效。您几乎只能通过引用获取
&self
,并调用一个方法。
//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();
    }
}
struct Container {
    clients: Vec<Box<ClientProxy>>,
}

fn main() {
    let mut container = Container {
        clients: Vec::new(),
    };
    let a = Box::new(MyActor { count: 3 });
    let b = Box::new(OtherActor { count: 4 });

    container.clients.push(a);
    container.clients.push(b);

    container
        .clients
        .iter()
        .for_each(|a| a.behave_like_client());
    //output : 
    //I am MyActor as Client, and my count is 3
    //I am OtherActor Client, and my count is 4
}