信頼性

関数が引数を検証している (C-VALIDATE)

RustでのAPIは「送るものに関しては厳密に、受け取るものに関しては寛容に」という堅牢性原則には縛られません。

代わりに、Rustコードは可能なかぎり入力の正しさを 検証 すべきです。

この検証は、以下のようにして行うことができます(より推奨されるものの順に並んでいます)。

静的な検証

不正な値を受け付けないよう引数の型を選んでください。

例えば次のようにします。


# #![allow(unused_variables)]
#fn main() {
fn foo(a: Ascii) { /* ... */ }
#}

このようにしてはいけません。


# #![allow(unused_variables)]
#fn main() {
fn foo(a: u8) { /* ... */ }
#}

ここでAsciiu8ラッパ であり、最上位ビットがゼロであることを保証します。 型安全なラッパを作る方法はnewtypeパターン(C-NEWTYPE)を参照してください。

静的な検証は型の境界にコストを押し込む(例えば、u8Asciiに変換しなければ受け付けない)ため、 実行時コストが掛かることは余りありません。 また、実行時ではなくコンパイル中にバグが検出されます。

一方、型を用いて表すことが困難あるいは不可能な特性も存在します。

動的な検証

入力を処理と同時に(あるいは必要ならば事前に)検証します。 動的な検証は静的な検証よりも実装が簡単ですが、いくつかの欠点があります。

  1. 実行時コスト (処理と検証を同時に行うことができない場合)
  2. バグの検出が遅れます
  3. パニックやResult/Option型による失敗ケースを呼び出し側のコードで処理しなければなりません

debug_assert!による動的な検証

プロダクションビルドにおいて高コストな検証を行わないようにできるかもしれません。

動的な検証のオプトアウト

チェックを行わないバージョンの関数を追加します。

チェックを行わない関数の名前の後ろに_uncheckedと付けたり、rawという名前のモジュールに置かれたりするのが一般的です。

チェックを行わない関数は(1)パフォーマンスがチェックよりも優先される場合 (2)入力が正しいと呼び出し側が確信している場合に使うことができます。

デストラクタが失敗しない (C-DTOR-FAIL)

デストラクタはパニック時にも実行されますが、その際にさらにデストラクタ内でパニックすると プログラムは強制終了します。

デストラクタでパニックする代わりに、Resultを返して失敗を通知するcloseメソッドのような、 失敗を確認することのできる破棄メソッドを追加してください。

ブロックする可能性のあるデストラクタには代替手段を用意する (C-DTOR-BLOCK)

デバッグが難しくなるため、デストラクタでブロックするような操作を行うべきではありません。 ブロックせずに破棄を行える別のメソッドを追加するべきです。