web-dev-qa-db-ja.com

Swift言語ガイドでは、「値が負でないことがわかっている場合でも」Intの使用を推奨しているのはなぜですか?

これはSwiftのプログラミングスタイル、特にIntUIntに関する質問です。

Swiftプログラミング言語ガイドは、変数が負でないことがわかっている場合でも、汎用の符号付き整数型Intを使用することをプログラマーにアドバイスしています。From the guide

UIntは、プラットフォームのネイティブのWordサイズと同じサイズの符号なし整数型が特に必要な場合にのみ使用してください。これが当てはまらない場合は、格納する値が負でないことがわかっている場合でも、Intが優先されます。型の安全性と型の推論で説明されているように、整数値にIntを一貫して使用すると、コードの相互運用性が向上し、異なる数値型間の変換が不要になり、整数型の推論に一致します。

ただし、UIntは32ビットアーキテクチャでは32ビット符号なし、64ビットアーキテクチャでは64ビット符号なしになるため、IntUIntよりも使用してもパフォーマンス上のメリットはありません。 。

対照的に、Swiftガイドは、後の例を示しています。

年齢= -3とする
assert(age> = 0、 "人の年齢はゼロ未満であってはなりません")
//これにより、年齢が> = 0ではないため、アサーションがトリガーされます

ここで、コードが次のように記述されている場合、runtimeの問題は、compile時にキャッチされる可能性があります。

let age:UInt = -3  
// this causes a compiler error because -3 is negative

UIntを使用すると、実行時ではなくコンパイル時に問題がキャッチされるケースは他にもたくさんあります(たとえば、コレクションにインデックスを付けるものなど)。

したがって、質問は、Swiftプログラミング言語ガイドサウンドのアドバイスであり、保存する値が非であることがわかっている場合でも、Intを使用する利点があります。ネガティブ」は、UIntを使用することの安全性の利点を上回ります。

追加注記:Swiftを数週間使用したことで、CocoaUIntが必要です。たとえば、AVFoundationフレームワークでは、「カウント」が必要な場所(サンプル/フレーム/チャネルなど)で符号なし整数を使用します。これらの変換Intへの値は、値がInt.maxより大きいという重大なバグにつながる可能性があります

54
j b

UIntの使用は、あなたが思っているほど安全ではないと思います。あなたが指摘したように:

let age:UInt = -3

コンパイラエラーが発生します。私も試しました:

let myAge:Int = 1
let age:UInt = UInt(myAge) - 3

また、コンパイラエラーが発生しました。ただし、以下のシナリオ(実際のプログラムでははるかに一般的です)にはコンパイラエラーはありませんでしたが、実際にはEXC_BAD_INSTRUCTIONのランタイムエラーが発生しました。

func sub10(num: Int) -> UInt {
    return UInt(num - 10) //Runtime error when num < 10
}
sub10(4)

と同様:

class A {
    var aboveZero:UInt
    init() { aboveZero = 1 }
}
let a = A()
a.aboveZero = a.aboveZero - 10 //Runtime error

これらが単純なIntsであった場合、クラッシュする代わりに、条件をチェックするコードを追加できます。

if a.aboveZero > 0 {
    //Do your thing
} else {
    //Handle bad data
}

UIntsを使用することに対する彼らのアドバイスを、暗黙的にラップされていないオプションを使用することに対する彼らのアドバイスと同等と見なすことさえあるかもしれません。ランタイムエラーを取得します(最も単純な場合を除く)。

18
Nick Shelley

それはあなたの質問で述べています。「整数値にIntを一貫して使用すると、コードの相互運用性が向上し、型の安全性と型の推論で説明されているように、異なる数値型間で変換する必要がなくなり、整数型の推論に一致します。」

これにより、UIntにIntを割り当てるなどの問題を回避できます。 UIntに割り当てられた負のInt値は、意図した負の値ではなく大きな値になります。両方のバイナリ表現は、タイプを区別しません。

また、どちらもクラスであり、一方は他方の子孫ではありません。構築されたクラスは、Intを受信して​​オーバーロードせずにUIntを受信できません。つまり、2つの間の変換は、フレームワークのほとんどがIntを受信するときに使用されるUIntの一般的なタスクです。 2つの間の変換も、重要なタスクになる可能性があります。

前の2つの段落では、「相互運用性」と「異なる数値タイプ間の変換」について説明しています。 UIntを使用しない場合に回避される問題。

1
BTRUE