中級 getting-started

Wasmにおけるエラーハンドリング

Wasmでエラーハンドリングが重要な理由

RustがWasm内でパニックすると、ブラウザには不可解な unreachable エラーが表示されます。適切なエラーハンドリングにより、RustのエラーをJavaScriptの意味のある例外に変換できます。

2つのアプローチ

1. Result<T, JsValue> — エラーがJS例外になる

#[wasm_bindgen]
pub fn safe_divide(a: f64, b: f64) -> Result<f64, JsValue> {
    if b == 0.0 {
        Err(JsValue::from_str("Division by zero"))
    } else {
        Ok(a / b)
    }
}

JavaScript側:

try {
    const result = safe_divide(10, 0);
} catch (e) {
    console.error(e); // "Division by zero"
}

2. Option<T> — 失敗時にundefinedを返す

#[wasm_bindgen]
pub fn find_user(id: u32) -> Option<String> {
    if id == 1 { Some("Alice".to_string()) } else { None }
}

JavaScript側:

const user = find_user(99);
if (user === undefined) {
    console.log("User not found");
}

エラー型の変換

? 演算子は Result と共に動作しますが、Wasmでは JsValue エラーが必要です:

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn parse_and_double(input: &str) -> Result<i32, JsValue> {
    let num: i32 = input.parse()
        .map_err(|e: std::num::ParseIntError| {
            JsValue::from_str(&format!("Parse error: {}", e))
        })?;
    Ok(num * 2)
}

カスタムエラー型

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct WasmError {
    code: u32,
    message: String,
}

#[wasm_bindgen]
impl WasmError {
    pub fn code(&self) -> u32 { self.code }
    pub fn message(&self) -> String { self.message.clone() }
}

fn make_error(code: u32, msg: &str) -> JsValue {
    let err = WasmError { code, message: msg.to_string() };
    JsValue::from(err)
}

パニックフック — 最後の手段

防ぎきれないパニックに対しては、パニックフックをインストールすることで読みやすいメッセージを取得できます:

use console_error_panic_hook;

#[wasm_bindgen(start)]
pub fn init() {
    console_error_panic_hook::set_once();
}

フックなし: RuntimeError: unreachable フックあり: panicked at 'index out of bounds: the len is 3 but the index is 5'

ベストプラクティス

すべきこと 避けるべきこと
エクスポートされた関数から Result<T, JsValue> を返す 関数をパニックさせる
?.map_err() でエラーを変換する エクスポートされた関数で .unwrap() を使う
console_error_panic_hook をインストールする パニックを無視する
意味のあるエラーメッセージを提供する 「エラーが発生しました」のような汎用メッセージを返す
「見つからない」ケースに Option<T> を使う センチネル値(-1、空文字列)を返す

試してみよう

Run をクリックして、エラーハンドリングパターンの動作を確認してください。各エラー型がどのように明確で説明的なメッセージを生成するかに注目してください。

試してみる

チャプタークイズ

すべての問題に正解してレッスンを完了しましょう