Hello everybody!
I have a problem with wrapping my head around move ||
. I suppose it is not actix
specific in any way.
Currently I have a few Actors I want to message each other:
use actix::prelude::*;
struct Main {}
impl Actor for Main {
type Context = Context<Self>;
}
struct GUI {
main: Addr<Main>,
}
impl Actor for GUI {
type Context = SyncContext<Self>;
}
struct Logging {
main: Addr<Main>,
}
impl Actor for Logging {
type Context = SyncContext<Self>;
}
I managed to wire it correctly, but have no idea why must it be like that.
Attempt 1
I know why this doesn't compile. Closure of the 1st arbiter steals maddr
then clones it, therefore there's noting to move to Logging
. I tried all variants with references, wit/without move, all errors are clear what's wrong.
#[actix_rt::main]
async fn main() {
let maddr = Main {}.start();
let gaddr = SyncArbiter::start(1, move || {
GUI {
main: maddr.clone(),
}
});
let laddr = SyncArbiter::start(1, move || {
Logging {
main: maddr.clone(),
}
});
// Irrelevant code to wait for ^C
}
Attempt 2
I have no idea, why this doesn't work... Both m1
and m2
IMHO can be cleanly moved into closures.
#[actix_rt::main]
async fn main() {
let maddr = Main {}.start();
let m1 = maddr.clone();
let gaddr = SyncArbiter::start(1, move || GUI { main: m1 });
let m2 = maddr.clone();
let laddr = SyncArbiter::start(1, move || Logging { main: m2 });
// Irrelevant code to wait for ^C
}
Error:
error[E0507]: cannot move out of `m1`, a captured variable in an `Fn` closure
--> cw4t_dmk_testers/src/bin/act.rs:29:59
|
28 | let m1 = maddr.clone();
| -- captured outer variable
29 | let gaddr = SyncArbiter::start(1, move || GUI { main: m1 });
| --------------------^^--
| | |
| | move occurs because `m1` has type `actix::Addr<Main>`, which does not implement the `Copy` trait
| captured by this `Fn` closure
Attempt 3
This works
#[actix_rt::main]
async fn main() {
let maddr = Main {}.start();
let m1 = maddr.clone();
let gaddr = SyncArbiter::start(1, move || GUI { main: m1.clone() });
let m2 = maddr.clone();
let laddr = SyncArbiter::start(1, move || Logging { main: m2.clone() });
// Irrelevant code to wait for ^C
}
I'm fine with double-cloning (this is done once per appplication run), but why?