Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

#[must_use] を追加するタイミング

#[must_use] 属性は、型や関数を明示的に考慮しなかったり、その出力を明示的に考慮しなかったりすることが、ほぼ確実にバグである場合に適用できます。

例として、Result#[must_use] です。なぜなら、それを考慮しないことは、呼び出し元がメソッドに失敗する可能性があることを認識していなかったことを示している可能性があるためです。

// `check_status` は失敗しないのでしょうか?それとも、その `Result` を確認し忘れたのでしょうか?
check_status();

saturating_add のような演算子も #[must_use] です。なぜなら、その出力を考慮しないことは、呼び出し元がそれらが左辺を変更しないことを認識していなかったことを示している可能性があるためです。

// 呼び出し元は、このメソッドが `a` を変更すると仮定しているかもしれません
a.saturating_add(b);

Iterator トレイトによって生成されるコンビネータは #[must_use] です。なぜなら、それらを使用しないことは、呼び出し元が Iterator が遅延評価され、消費しない限り実際には何もしないことを認識していなかったことを示している可能性があるためです。

// 呼び出し元は、`collect` や `count` などを呼び出さない限り、
// このコードが何もしないことを認識していないかもしれません。
v.iter().map(|x| println!("{}", x));

一方、thread::JoinHandle#[must_use] ではありません。なぜなら、投げっぱなしの処理をスポーンすることは正当なパターンであり、呼び出し元にハンドルを明示的に無視することを強制するのは、バグの兆候というよりも迷惑になり得るためです。

thread::spawn(|| {
    // このバックグラウンド処理は待機されません
});

レビュアー向け

#[must_use] によって呼び出し元が値を明示的に無視することになる、正当なユースケースがないか探してください。これらが一般的であれば、#[must_use] はおそらく適切ではありません。

#[must_use] 属性は警告を生成するだけなので、技術的にはいつでも導入できます。ただし、迷惑な警告が蓄積するのを避けるため、既存の型や関数に新しい #[must_use] 属性を追加する前に、@rust-lang/libs に意見を求めてください。