これは、型に範囲チェックが含まれていない言語で一般的なイディオムです。「範囲外」の値は、いくつかの条件の 1 つを示すために使用されます。ここで、戻り値は 2 つのことを示します: 1) 見つかった文字と 2) 見つかった場所。-1 fornot found
と非負のインデックス for を使用すると、これらの両方が 1 つの値に簡潔にエンコードされ、インデックスを返す必要がないfound
という事実が示されます。not-found
Ada や Pascal など、範囲チェックが厳密な言語では、メソッドは (疑似コード) として実装される場合があります。
bool indexOf(c:char, position:out Positive);
Positive
int のサブタイプですが、負でない値に制限されています。
これにより、見つかった/見つからないフラグが位置から分離されます。位置は出力パラメータとして提供されます - 基本的に別の戻り値です。また、指定された位置から検索を開始するための in-out パラメータにすることもできます。-1 を使用して not-found を示すことは、Positive 型の範囲チェックに違反するため、ここでは許可されません。
Java の代替手段は次のとおりです。
- 例外をスローします。これは、文字が見つからないことは例外的な条件ではないため、ここでは適切な選択ではありません。
- 結果をいくつかのメソッドに分割し
boolean indexOf(char c); int lastFoundIndex();
ます。これは、オブジェクトが状態を保持する必要があることを意味します。これは、状態がスレッド ローカル ストレージに格納されるか、同期が使用されない限り、並行プログラムでは機能しません (すべてかなりのオーバーヘッド)。
- のように、位置と見つかったフラグを別々に返し
boolean indexOf(char c, Position pos)
ます。ここで、位置オブジェクトの作成は不要なオーバーヘッドと見なされる場合があります。
- 複数値の戻り型を作成する
そのような
class FindIndex {
boolean found;
int position;
}
FindIndex indexOf(char c);
戻り値は明確に分離されていますが、オブジェクト作成のオーバーヘッドが発生します。FindIndex
その一部は、をパラメータとして渡すことで軽減できます。
FindIndex indexOf(char c, FindIndex start);
ちなみに、複数の戻り値は Java (oak) の一部になる予定でしたが、リリースまでの時間を短縮するために 1.0 より前に廃止されました。ジェームズ・ゴズリングは、彼らが含まれていればよかったと言います。それはまだ望まれる機能です。
私の見解では、マジック値の使用は、オブジェクト作成のオーバーヘッドを過度に必要とせずに、多値の結果 (フラグと値) を単一の戻り値にエンコードする実用的な方法です。
ただし、マジック値を使用する場合、それらが関連する API 呼び出し間で一貫している場合は、操作がはるかにうまくいきます。例えば、
// get everything after the first c
int index = str.indexOf('c');
String afterC = str.substring(index);
への呼び出しで -1 を使用するsubstring
とIndeOutOfBoundsException
. 代わりに、負の値が文字列の末尾から始まると見なされる場合、-1 で呼び出されたときに部分文字列が "" を返す方が一貫性があった可能性があります。エラー状態の魔法の値を批判する人は、戻り値は無視できる (または正であると見なす) ことができると言っています。これらの魔法の値を便利な方法で処理する一貫した API は、-1 をチェックする必要性を減らし、よりクリーンなコードを可能にします。