我可以将Int64直接转换为Int吗?

时间:2015-09-26 03:56:53

标签: ios swift sqlite.swift

我最近一直在使用SQLite.swift来构建我的app数据库。 我正在使用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
}

这是正确的吗?

当然我测试了它。它确实有效,但我正在阅读this question in Stackoverflow

似乎我可能遇到32位设备的问题......

如果这是错误的,我如何将Int64投射到Int

4 个答案:

答案 0 :(得分:28)

通过将Int64值传递给Int初始化程序,将Int64转换为Int将始终在64位计算机上运行,​​并且会在32位计算机上崩溃如果整数超出范围Int32.min ... Int32.max

,则为-bit机器

为了安全起见,使用init(truncatingIfNeeded:)初始值设定项(以前在早期的Swift版本中称为init(truncatingBitPattern:))来转换值:

return Int(truncatingIfNeeded: rowid)

在64位计算机上,truncatingIfNeeded将无效;您只需获得Int(无论如何都与Int64相同)。

在32位机器上,这将丢弃前32位,但它们都是零,然后你没有丢失任何数据。因此,只要您的值适合32位Int,就可以在不丢失数据的情况下执行此操作。如果您的值超出Int32.min ... Int32.max范围,则会将Int64的值更改为适合32位Int的值,但不会崩溃。

您可以在Playground中查看其工作原理。由于Playground中的Int是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 coalescing operator 来提供默认值:

// return 0 if rowid is too big to fit into an Int on this device
return Int(exactly: rowid) ?? 0

答案 1 :(得分:2)

如果您确信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
    ...
}

在特定的rowid情况下,使用Int64而非Int是故意的API设计选择,而将其截断为Int可能是一个错误。

答案 2 :(得分:0)

事实上,我也一直在使用这个框架,基本上我只使用了相反的解决方案。只要你看到那些类型不匹配就行了

Int64(yourInt) 

(使用Xcode 7,Swift 2.0测试)

答案 3 :(得分:0)

这是一个痛苦的屁股。它比Objective-C更具纪念意义。但是,这是您的操作方式。

如果您使用的是UInt64,就可以这样做。

let thatVarYouWantToConvert: UInt64 = 1
let myInt: Int = Int(exactly:thatVarYouWantToConvert ?? 0)

如果您使用的是UInt64?,就可以这样做。

let thatVarYouWantToConvert: UInt64? = 1
let myInt: Int = Int(exactly:thatVarYouWantToConvert ?? 0) ?? 0

就像我说的那样,“比起Objective-C,这真是太愚蠢了。”

在Swift 4.2,Xcode 10.2.1中进行了测试