クロージャ内で外側のスコープの変数をmutableな変数に同名で束縛したいときに、外側の変数の不変に保つために、 以下のようなマクロを使っている。
macro_rules! enclose {
$( $x:ident ),*) $y:expr ) => {
( ({
$(let mut $x = $x.clone();)*
$y
}
};
}
以下のような感じで書ける。
let sdk = agones::Sdk::new().map_err(|_| "Could not connect to the sidecar. Exiting!")?;
let _health = thread::spawn(enclose! {(sdk) move || {
loop {
match sdk.health() {
, Ok(_)) => {
(sprintln!("Health ping sent");
= s;
sdk },
, Err(e)) => {
(sprintln!("Health ping failed : {:?}", e);
= s;
sdk }
}
thread::sleep(Duration::from_secs(2));
}
}});
thread::spawn
に渡しているクロージャ内では、sdk変数を特定の条件で再束縛しているため、sdk変数はmutableである必要がある。
マクロなしでmutableなsdk変数を作ろうとcloneしてしまうと、シャドウイングによって外側のスコープのimmutableなsdk変数を後続の処理で使うことができなくなってしまう。
上記の enclose
マクロは、このシャドウイングを防止する。健全なマクロバンザイ。
なお、自分はマクロ素人 & ちょっと前のバージョンでこのマクロを使ったので、Rust2018ではもっといい方法があるかもしれない。 あしからず。