RustでWebAssembly: spawn_local() へ渡すasync functionに状態を持ったObjectを渡したいときの抜け道
はじめに
spawn_local()
は wasm-bindgen で、asyncな関数を実行する便利な(JS側を介さない)方法ですが、
pub fn spawn_local<F>(future: F)
where
F: Future<Output = ()> + 'static,
という型になっていて Futureが使う参照は'static
なlifetimeをもつものしか渡せません。
つまりこれは、以下のように書くことができないということになります。
impl MyApp {
fn some_func(&mut self) {
spawn_local(my_async_process(&mut self)); // &mut selfの lifetimeがstaticではないのでダメ
}
}
この制約が厄介だなーと思っていたのですが、抜け道を見つけた(いや、最初からそこにあったのでしょうが)のでメモしておきます。Rust初心者にはちょっと気が付きにくいなぁと思ったので。
抜け道
'static MyApp
を用意しておく
'static MyApp
を用意しておくこれは 前回 考えた方法で、まあ確かにこれならうまくいきます。
しかし、my_async_process の中に入れたいのが staticにできるものとは限りません。複数あるObjectとかだとこの方法は使いにくいです。(もちろん、なんとかはできますが)。
Rc<RefCell<MyApp>>
を渡す
参照(&)を渡すことはできないですが、 Rc
構造体を渡すことはできるようです。
なので、spawn_localしたい部分に、いつもの Rc<RefCell<MyApp>>
みたいなのを持ち込むことがでていれば渡すことができます。
Localで作成した普通のObjectならこの方法が良いかもしれないです。Box<HogeHoge>
とかでも良いような気がします。
// 仮にこれをselfが持っていれば渡せることになる
let x: Rc<RefCell<MyApp>> = Rc::new(RefCell::new(MyApp::new()));
spawn_local(my_async_process_with_ref_cell(x.clone(), self.clicks));
...
pub async fn my_async_process_with_ref_cell(my_app: Rc<RefCell<MyApp>>, param: u32) {
// 何か await とかしたりできる(fetchとか)
// spawn_local() で使えるのは static な 参照しかないが、 Rcに包まれたものは有効。
my_app.borrow_mut().async_count += param;
}
Raw Pointerを渡す
Rustには 「参照(&
, &mut
)」とは別に「RawPointer(*
)」というのがあります(というのを思い出した)。
https://doc.rust-lang.org/reference/types/pointer.html
「参照」の方は lifetime が管理されていたり、&mut
が排他的な扱いをうけたりしていてRustの特別な感じを醸し出していますが、「RawPointer」にはそういうのがありません。代わりに Dereferenceするときは NULLかもしれないし、もう値がないかもしれないので unsafe {}
で囲わないといけないことになっています。で、 spawn_local は 「'static
ではない参照」を禁じているのであって、RawPointerについては何も言及していません。なので、実はRawPointerを渡すことができるようです。
つまり、こんな抜け道がありました。んー気が付かなかった。
spawn_local(my_async_process_with_raw_pointer(
self as *mut MyApp,
self.clicks,
));
...
pub async fn my_async_process_with_raw_pointer(my_app: *mut MyApp, param: u32) {
// *mut MyApp は 「参照」ではなく 「RawPointer」
// spawn_local() で使える「参照」は static な 参照しかないが、 Raw Pointerなら渡せる!!
unsafe {
(*my_app).async_count += param;
}
}
さいごに
まあ、どの方法もケースバイケースで使い分けると良さそうです。
いろいろやり方はあるものですね。
Author And Source
この問題について(RustでWebAssembly: spawn_local() へ渡すasync functionに状態を持ったObjectを渡したいときの抜け道), 我々は、より多くの情報をここで見つけました https://qiita.com/mokemokechicken/items/3dcd16a7b51f9a07c67d著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .