34

最近、SQLite.swift を使用してアプリ データベースを構築しています。ドキュメントで説明されているように、すべてのINTEGER列を型で定義しています。Int64

しかし、時々、私はそれInt64がただである必要がありIntます。だから私の質問は、私がこれを行う場合です:

//Create a table with Int instead of Int64
let test_id = Expression<Int>("test_id")
let tests = db["tests"]

db.create(table: tests, ifNotExists: true){ t in
    t.column(test_id)
}


class func insertTest(t: Int) -> Int{
    //insert.rowid returns an Int64 type
    let insert = tests.insert(test_id <- t)
    if let rowid = insert.rowid{
        //directly cast Int64 into Int
        return Int(rowid)
    }
    return 0
}

それは正しいでしょうか?

もちろん、私はそれをテストしました。それは機能しますが、私はこの質問をStackoverflowで読んでいました

そして、32ビットデバイスで問題が発生する可能性があるようです...

これが間違っている場合、どうすれば にキャストできInt64ますIntか?

4

4 に答える 4

55

値をイニシャライザに渡して を に変換するInt64と、64 ビット マシンでは常に機能し、32 ビット マシンでは整数が範囲外の場合にクラッシュします。IntInt64IntInt32.min ... Int32.max

安全のために、init(truncatingIfNeeded:)イニシャライザ (init(truncatingBitPattern:)以前の Swift バージョンでは以前は呼ばれていました) を使用して値を変換します。

return Int(truncatingIfNeeded: rowid)

64 ビット マシンでは、truncatingIfNeededは何もしません。を取得するだけですInt(とにかくと同じサイズInt64です)。

32 ビット マシンでは、これにより上位 32 ビットが破棄されますが、それらがすべて 0 の場合、データは失われていません。したがって、値が 32 ビットに収まる限り、Intデータを失うことなくこれを行うことができます。値が範囲外の場合、これにより の値が32 ビットに適合するInt32.min ... Int32.max値に変更されますが、クラッシュはしません。Int64Int


これが Playground でどのように機能するかを確認できます。In Inta Playground は 64 ビットIntであるため、 を明示的に使用しInt32て 32 ビット システムの動作をシミュレートできます。

let i: Int64 = 12345678901  // value bigger than maximum 32-bit Int

let j = Int32(truncatingIfNeeded: i)  // j = -539,222,987
let k = Int32(i)                        // crash!

Swift 3/4 の更新

これがまだ機能することに加えてinit(truncatingIfNeeded:)、Swift 3 では、ある整数型を別の整数型に安全に変換するための失敗可能な初期化子が導入されています。を使用init?(exactly:)すると、あるタイプを渡して別のタイプを初期nil化でき、初期化が失敗した場合に戻ります。返される値はオプションで、通常の方法でアンラップする必要があります。

例えば:

let i: Int64 = 12345678901

if let j = Int32(exactly: i) {
    print("\(j) fits into an Int32")
} else {
    // the initialization returned nil
    print("\(i) is too large for Int32")
}

これにより、nil 合体演算子を適用して、変換が失敗した場合にデフォルト値を提供できます。

// return 0 if rowid is too big to fit into an Int on this device
return Int(exactly: rowid) ?? 0
于 2015-09-26T04:32:33.403 に答える
3

Int64値を として正確に表現できると確信している場合Intは、次のように使用しますInt(truncatingIfNeeded:)

let salary: Int64 = 100000
let converted = Int(truncatingIfNeeded: salary)

32 ビット デバイスをターゲットとするビルドの場合、 の範囲はIntと同じ -2147483648 ~ 2147483647 に制限されInt32ます。その範囲外の値は、静かに上位ビットが破棄されます。これにより、多くの場合反対の符号のガベージが発生します。

値が範囲外である可能性があり、その状態を処理したい場合は、次のように使用しますInt(exactly:)

if let converted = Int(exactly: salary) {
    // in range
    ... converted ...
} else {
    // out-of-range
    ...
}

行 ID の特定のケースでは、Int64むしろ使用Intするのは意図的な API 設計の選択であり、切り捨てるIntことはバグである可能性があります。

于 2018-09-13T04:48:55.223 に答える