如何实现一个工厂特质,返回具有匹配类型参数的通用值?

6
考虑以下代码(简化但可编译):
use std::sync::Arc;

pub trait ActorRef<Message> { /* ... */ }
pub trait Actor<Message> { /* ... */ }
pub trait ActorSpawner {
    /// Spawns a new actor returning an actor ref 
    /// for passing messages to it.
    fn spawn<Message,A,R>(actor: A) -> Arc<R>
        where R: ActorRef<Message>, A: Actor<Message>;
}

能否实现ActorSpawner::spawn或者通过其他方式实现类似功能?

思路

为了简化问题,代码已被简化到核心部分。

通常,Actor应该具有可变状态,该状态通过处理消息进行更改(示例中缺少处理方法)。您可以生成一个Actor并可以通过ActorRef与其通信(示例中缺少发送方法)。

我想允许以不同的方式"生成"Actor。例如,每个actor可能会有一个线程来处理消息。或者处理可能在共享线程池上完成。

其他代码可能依赖于创建进一步的actors。 应该抽象使用的底层机制。由于特质ActorSpawner.

我的解决方案尝试

假设我们对ActorActorRef都有一些虚假实现:

struct NoopActor;
impl<Message> Actor<Message> for NoopActor {}

struct DeadRef;
impl<Message> ActorRef<Message> for DeadRef {}

现在可以使用这些虚拟实现来实现特质。

以下是我的第一次尝试:

struct DeadActorSpawner;
impl ActorSpawner for DeadActorSpawner {
    fn spawn<Message,A,R>(actor: A) -> Arc<R>
        where R: ActorRef<Message>, A: Actor<Message> 
    {
        Arc::new(DeadRef)
    }
}

导致出现此错误:
error[E0308]: mismatched types
  --> src/main.rs:29:18
   |
29 |         Arc::new(DeadRef)
   |                  ^^^^^^^ expected type parameter, found struct `DeadRef`
   |
   = note: expected type `R`
              found type `DeadRef`

或者另一个例子:
struct DeadActorSpawner;
impl ActorSpawner for DeadActorSpawner {
    fn spawn<Message,A,R>(actor: A) -> Arc<DeadRef>
    {
        Arc::new(DeadRef)
    }
}

导致出现以下错误:

error[E0053]: method `spawn` has an incompatible type for trait
  --> src/main.rs:25:42
   |
12 |     fn spawn<Message, A, R>(actor: A) -> Arc<R>
   |                                          ------ type in trait
...
25 |     fn spawn<Message, A, R>(actor: A) -> Arc<DeadRef> {
   |                                          ^^^^^^^^^^^^ expected type parameter, found struct `DeadRef`
   |
   = note: expected type `fn(A) -> std::sync::Arc<R>`
              found type `fn(A) -> std::sync::Arc<DeadRef>`

我已经尝试了许多其他方法,包括在ActorActorRef中使用关联类型来解决Message的问题,但都没有成功。


2
我想预先要求更多的信息。目前我能给出的唯一明确答案是:“你所要求的是不可能的”。你能解释一下所有通用类型的作用吗?它们是否真的需要是通用的,或者说,实现ActorSpawner特质可以向调用者指定特定的ActorRef/Actor/Message组合,这样做是否可行? - DK.
嗨DK,如果ActorSpawner可以决定它生成的ActorRefs的类型,那么这将是可以接受的。但由于kers的解决方案不需要这样做,所以没有理由这样做。无论如何,感谢您对此问题的关注! - Peter Kolloch
1个回答

4

是否可以实现ActorSpawner::spawn

是的,但我认为没有有用的实现方式。

或者通过其他签名实现类似的功能

我相信您希望返回一个Arc<ActorRef<Message>>。因此,您可以通过ActorSpawner特征使用DeadActorSpawner而不知道Dead*类型。

实际上,您尝试将spawn函数专门化为返回Arc<DeadRef>。我修改了您的ActorSpawner以返回特征对象:

pub trait ActorSpawner {
    fn spawn<Message, A>(actor: A) -> Arc<ActorRef<Message>> where A: Actor<Message>;
}

struct DeadActorSpawner;
impl ActorSpawner for DeadActorSpawner {
    fn spawn<Message, A>(actor: A) -> Arc<ActorRef<Message>>
        where A: Actor<Message>
    {
        Arc::new(DeadRef)
    }
}

操场示例


谢谢,@ker!那是我尝试过的东西,但没有意识到我需要夜间rust或额外的Box。 - Peter Kolloch
希望我现在已经以易懂的方式解释了有问题的代码的思路。再次感谢您的帮助。 - Peter Kolloch
我在你的代码基础上进行了一些扩展/修改,添加了一个自变量和一个使用代码的小例子:http://is.gd/AIWMgs - Peter Kolloch

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