Prompt
JSのPromiseにあたるものはRustでは?
JSのPromiseに相当するものは、Rustでは Future と呼ばれるよ!
そして、JSでおなじみの async / await 構文も、Rustにはバッチリ備わっているんだ。
でも、情報工学的に見ると、Rustの Future はJSの Promise よりもずっと**「低燃費で効率的」**に設計されているんだ。その決定的な違いと仕組みを解説するぜ!🚀
1. 決定的な違い:JSは「能動」、Rustは「受動」
ここが一番の驚きポイントだ!
-
JSのPromise (Push型):
Promiseを作った瞬間、バックグラウンドで計算が自動的に開始される。
-
RustのFuture (Pull型):
Future を作っただけでは何も起きない。誰かが「進捗どうですか?(poll)」と尋ねるまで、一歩も動かない「怠け者」なんだ。
2. 実行エンジン「Runtime」の存在
JSはブラウザやNode.jsといった「実行環境」が最初から非同期処理を回してくれるよね。でも、Rustには標準ライブラリにその「エンジン」が含まれていないんだ。
だから、Rustで Future を動かすには tokio や async-std といった外部の 「非同期ランタイム(Executor)」 を使う必要があるよ。
Rust
// [dependencies] tokio = { version = "1", features = ["full"] }
#[tokio::main] // これがランタイムを起動する魔法の言葉!
async fn main() {
let future = say_hello(); // これだけじゃ何も起きない
future.await; // ここでランタイムが Future を進める!
}
async fn say_hello() {
println!("Hello, Async World!");
}
3. 状態遷移と poll メソッド
情報工学徒の君なら、裏側で何が起きているか気になるよね。
Future は内部的に ステートマシン(状態遷移図) に変換されているんだ。
-
ランタイムが
poll()メソッドを呼ぶ。 -
計算が終わっていなければ
Poll::Pendingを返す。 -
何か(I/O待ちなど)が進展したら、ランタイムに通知が飛ぶ。
-
ランタイムが再度
poll()を呼び、終わっていればPoll::Ready(値)を返す。
この「必要なときだけ呼び出す」仕組みのおかげで、Rustは大量の非同期タスクを極めて少ないメモリ消費で捌けるんだ。
💡 見落とされがちな落とし穴:JoinHandle とキャンセル
JSのPromiseは一度走り出すと止めるのが大変だけど、Rustの Future は「誰にも poll されなくなった瞬間」に**自動的に計算がキャンセル(ドロップ)**されるんだ。
-
並列実行したいとき:
tokio::spawnを使う(JSのPromiseに近い挙動になる)。 -
複数を待ち合わせたいとき:
tokio::join!やfutures::future::join_allを使う(JSのPromise.all相当だね)。
🏁 まとめ
| 特徴 | JavaScript (Promise) | Rust (Future) |
|---|---|---|
| 開始タイミング | 定義した瞬間 | .await された瞬間 |
| 実行環境 | エンジン内蔵 | 外部ランタイム (tokio等) が必要 |
| キャンセル | 困難 | ドロップするだけでOK |
| オーバーヘッド | 若干ある | ゼロコスト抽象化に近い |
JSから来た人は、最初は「.await し忘れると何も起きない」という罠にハマりやすい。でも、これを知っていれば君はもう大丈夫だ!