У меня есть два актера Actix. MyActor1
определяет общий признак, который реализует одно из его полей. MyActor2
не нужно определять T
, и я не могу понять, как вызывать MyActor1::from_registry()
из обработчиков сообщений MyActor2
, не зная, к какому типу относится T
.
Я пробовал варианты этого:
let addr: Addr<MyActor1<T>> = MyActor1::from_registry();
Это не работает, потому что я не знаю, где/как определить T
, если только оно не определено в struct MyActor2<T: Thing>
, а затем добавлено в impl<T> Handler<Msg> for MyActor2<T> where T:...
.
Я также пробовал это, но это не работает, потому что Thing
не реализует Default
(потому что это черта):
let addr: Addr<MyActor1<Thing>> = MyActor1::from_registry();
Вот пример, который я использую:
Груз.томл
[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>
во время выполнения на основе какого-то аргумента командной строки.
Вы буквально ищете синтаксис let addr = MyActor1::<One>::from_registry()
?
Если да, то этот вопрос будет дубликатом Как мне указать тип значения, когда нет параметров или атрибутов типа?.
MyActor1
как MyActor1<Two>
во время выполнения — это не то, как работают типизированные языки статически.
TL;DR: MyActor1
это не тип, это план.
Когда вы объявляете struct Foo<T>
, Foo
не является типом, это план для компилятора по созданию типов или, как говорят в компьютерных науках, конструктор типов.
Если у вас есть чертежи дома, вы не можете открыть дверь чертежа и пойти вздремнуть в спальне: спальни нет, есть представление о том, как будет выглядеть спальня, когда дом будет построен.
То же самое применимо и здесь. Вы не можете использовать конструктор типов там, где требуется тип.
У вас осталось 3 решения:
MyActor1
типом, убрав параметр T
; например, он может хранить T
как Box<Thing>
.MyActor2
универсальным, добавив параметр T
.Какое решение является лучшим в вашем случае, будет в значительной степени зависеть от вашего варианта использования, и я ненавижу давать какие-либо советы, основанные на сокращенном примере.
Я не понимаю логики вашего вопроса. Вы создали общий актер, а это значит, что может быть несколько актеров с разными конкретными типами (например,
MyActor1<i32>
иMyActor1<bool>
). Если ты не знает, на какого актера вы хотите сослаться, как будет код?