从另一个未定义 T 的 actor 处理程序调用 MyActor::from_registry() 时如何确定类型注释?

How do I determine the type annotation while calling MyActor::from_registry() from another actor's handler that doesn't define T?

我有两个 Actix 演员。 MyActor1 定义了其字段之一实现的通用特征。 MyActor2 不需要定义 T 并且我不知道如何在不知道 T 映射到什么类型的情况下从 MyActor2 消息处理程序调用 MyActor1::from_registry() .

我试过这个的变体:

let addr: Addr<MyActor1<T>> = MyActor1::from_registry();

这不起作用,因为我不知道 where/how 定义 T,除非它也在 struct MyActor2<T: Thing> 上定义,然后添加到 impl<T> Handler<Msg> for MyActor2<T> where T:...

我也试过了,但它不起作用,因为 Thing 没有实现 Default(因为它是一个特征):

let addr: Addr<MyActor1<Thing>> = MyActor1::from_registry();

这是我正在使用的示例:

Cargo.toml

[package]
name = "actix-example"
version = "0.1.0"
authors = ["me"]
edition = "2018"

[dependencies]
actix = "0.8.1"

main.rs

#![allow(dead_code)]

use actix::prelude::*;

trait Thing {
    fn name(&self) {}
}

#[derive(Default)]
struct One;
impl Thing for One {}

#[derive(Default)]
struct Two;
impl Thing for Two {}

// MyActor1
#[derive(Default)]
struct MyActor1<T: Thing> {
    thing: T,
}

impl<T> Actor for MyActor1<T>
where
    T: Thing + 'static + Default,
{
    type Context = Context<Self>;
}
impl<T> Supervised for MyActor1<T> where T: Thing + 'static + Default {}
impl<T> SystemService for MyActor1<T> where T: Thing + 'static + Default {}
impl<T> Handler<Msg> for MyActor1<T>
where
    T: Thing + 'static + Default,
{
    type Result = ();
    fn handle(&mut self, _msg: Msg, _ctx: &mut Context<Self>) {}
}

// MyActor2
#[derive(Default)]
struct MyActor2;

#[derive(Message)]
struct Msg;
impl Actor for MyActor2 {
    type Context = Context<Self>;
}
impl Supervised for MyActor2 {}
impl SystemService for MyActor2 {}

impl Handler<Msg> for MyActor2 {
    type Result = ();
    fn handle(&mut self, _msg: Msg, _ctx: &mut Context<Self>) {
        let addr = MyActor1::from_registry();
    }
}

fn main() {
    let sys = System::new("test");
    let act1 = MyActor1 {
        thing: One::default(),
    };
    let act2 = MyActor2::default();
    actix::SystemRegistry::set(act1.start());
    actix::SystemRegistry::set(act2.start());
    let _ = sys.run();
}

当运行代码时,我得到这个错误:

error[E0283]: type annotations required: cannot resolve `_: Thing`
  --> src/main.rs:50:20
   |
50 |         let addr = MyActor1::from_registry();
   |                    ^^^^^^^^^^^^^^^^^^^^^^^
   |
note: required by `MyActor1`
  --> src/main.rs:15:1
   |
15 | struct MyActor1<T: Thing> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^

我知道这解决了这个例子:

let addr: Addr<MyActor1<One>> = MyActor1::from_registry();

如果我在运行时不知道 MyActor1<T> 是什么,我该怎么办?例如,也许我有一些代码根据一些命令行参数在运行时将 MyActor1 初始化为 MyActor1<Two>

TL;DR: MyActor1 不是类型,而是蓝图。


当您声明 struct Foo<T> 时,Foo 不是类型,它是编译器创建类型的蓝图,或者,按照计算机科学的说法, 类型构造函数.

如果你有房子的设计图,你不能打开设计图的门去卧室睡午觉:没有卧室,有一个想法,一旦房子建成后卧室会是什么样子建成。

这里同样适用。您不能在需要 type 的地方使用 type 构造函数


您还剩下 3 个解决方案:

  • 使MyActor1成为类型,移除参数T;例如,它可以将 T 存储为 Box<Thing>.
  • 使 MyActor2 成为泛型,添加参数 T.
  • 实施一些 run-time 发现,例如使用 type-map.

在你的案例中哪个是最好的解决方案将在很大程度上取决于你的用例,我不愿意根据简化的例子给出任何建议。