Rust async は意外とツライ件
忘れないようにサクサクとメモ書きです。
そんな私がRust 1.39でasync/awaitが入ったということで喜んでがりがり使ってみようと
思ったけどあんまりうまく行かなかったって話です。
Rust初心者がasync/await使ってハマったのは・・・・
- traitの実装ではではasync関数使えない。ただしasync-traitのクレートを使うと行けるようです。
- trait内のasync関数ではSendではなくSyncの実装が必要っぽい?試行錯誤していたらSyncが足りないみたいなエラーが出たりしてまいました。
- async fn で定義した関数で再起呼び出しすると、BoxFutureを戻り値にとか言われて混乱したので最終的に通常の関数内にasync blockを作ってblock_onメソッドで実行するようにした(本末転倒気味)
- 上記のような関数に対して、Fn(a: &str) -> bool みたいな関数をフィルタとして引数として取ろうとしたら、スレッドセーフじゃないからダメだぜ!って言われて途方に暮れる。
きっとネイティブで動く故の制限だったりするのだろうか。特にスレッドセーフにならないような状況が推測できるときにコンパイルエラーになるようです。
きっと回避策はあるのでしょうが、どうすりゃいいの!?!?ってなっていまして(;´∀`)
impl Hoge { fn search_dirs(&mut self, dir: PathBuf, func: Boxbool>) -> Result<Vec > { let mut result:Vec = Vec::new(); let result_task:BoxFuture<Result<Vec >> = async move { let mut dir = fs::read_dir(dir).await?; while let Some(entry) = dir.next().await { let entry = entry?; let file_type = entry.file_type().await?; if file_type.is_dir() { // ディレクトリの場合は再起で深堀していきます let r = self.search_dirs(entry.path(), func)?; result = result.into_iter().chain(r.into_iter()).collect(); } else { if func(&entry.path()) { result.push(entry.path()); } } } Ok(result) }.boxed(); async_std::task::block_on(result_task) } }
例えばこんな感じに作ってたら、
`dyn for<'r> std::ops::Fn(&'r async_std::path::pathbuf::PathBuf) -> bool` cannot be sent between threads safely
とか言われちゃいましてね。
まだまだ勉強不足を痛感するところです(´・ω・`)
C#だと結構この辺意識せずすいすい使えたので、シンドイといか結構新鮮というかw
メモ書きなんでこの辺で。。。