简体   繁体   English

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

[英]Can I cast Int64 directly into Int?

I've been using SQLite.swift lately to build my app database. 我最近一直在使用SQLite.swift来构建我的app数据库。 And I'm defining all my INTEGER columns with a Int64 type, like the documentation explains. 我正在使用Int64类型定义所有INTEGER列,就像文档说明的那样。

But every once in a while I need that Int64 to be just Int . 但每隔一段时间我就需要Int64才是Int So my question is, if I do this: 所以我的问题是,如果我这样做:

//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
}

Will it be correct? 这是对的吗?

Of course I tested it. 当然我测试了它。 And it does works, but I was reading this question in Stackoverflow 它确实有效,但我正在Stackoverflow中阅读这个问题

And it seems that I could have a problem with 32 bits devices... 似乎我可能遇到32位设备的问题......

If this is wrong, how can I cast Int64 into Int ? 如果这是错误的,我如何将Int64转换为Int

Converting an Int64 to Int by passing the Int64 value to the Int initializer will always work on a 64-bit machine, and it will crash on a 32-bit machine if the integer is outside of the range Int32.min ... Int32.max . 变换所述Int64Int由传递Int64值的Int初始化将始终在64位机器上工作,这将在32位机器上崩溃,如果此整数为范围外Int32.min ... Int32.max

For safety use the init(truncatingIfNeeded:) initializer (formerly known as init(truncatingBitPattern:) in earlier Swift versions) to convert the value: 为安全起见,使用init(truncatingIfNeeded:)初始化程序(以前在早期的Swift版本中称为init(truncatingBitPattern:) )来转换值:

return Int(truncatingIfNeeded: rowid)

On a 64-bit machine, the truncatingIfNeeded will do nothing; 在64位机器上, truncatingIfNeeded将不执行任何操作; you will just get an Int (which is the same size as an Int64 anyway). 您将获得一个Int (无论如何都与Int64相同)。

On a 32-bit machine, this will throw away the top 32 bits, but it they are all zeroes, then you haven't lost any data. 在32位机器上,这将丢弃前32位,但它们都是零,然后你没有丢失任何数据。 So as long as your value will fit into a 32-bit Int , you can do this without losing data. 因此,只要您的值适合32位Int ,就可以在不丢失数据的情况下执行此操作。 If your value is outside of the range Int32.min ... Int32.max , this will change the value of the Int64 into something that fits in a 32-bit Int , but it will not crash. 如果您的值超出Int32.min ... Int32.max范围,这将把Int64的值更改为适合32位Int ,但不会崩溃。


You can see how this works in a Playground. 您可以在Playground中看到它的工作原理。 Since Int in a Playground is a 64-bit Int , you can explicitly use an Int32 to simulate the behavior of a 32-bit system. 由于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!

Update for Swift 3/4 更新Swift 3/4

In addition to init(truncatingIfNeeded:) which still works, Swift 3 introduces failable initializers to safely convert one integer type to another. 除了仍然有效的init(truncatingIfNeeded:) ,Swift 3还引入了可用的初始化器,以便将一个整数类型安全地转换为另一个整数类型。 By using init?(exactly:) you can pass one type to initialize another, and it returns nil if the initialization fails. 通过使用init?(exactly:)您可以传递一种类型来初始化另一种类型,如果初始化失败则返回nil The value returned is an optional which must be unwrapped in the usual ways. 返回的值是可选的,必须以通常的方式解包。

For example: 例如:

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")
}

This allows you to apply the nil coalescing operator to supply a default value if the conversion fails: 这允许您应用nil合并运算符以在转换失败时提供默认值:

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

If you're confident that the Int64 value can be represented exactly as an Int , use Int(truncatingIfNeeded:) , eg: 如果您确信Int64值可以完全表示为Int ,请使用Int(truncatingIfNeeded:) ,例如:

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

For builds targeting 32-bit devices, the range for Int is limited to -2147483648 through 2147483647, the same as Int32 . 对于针对32位设备的构建, Int的范围限制为-2147483648到2147483647,与Int32相同。 Values outside of that range will quietly have their high-order bits discarded. 超出该范围的值将悄然丢弃其高位。 This results in garbage, often of the opposite sign. 这导致垃圾,通常是相反的标志。

If the value might be out of range, and you want to handle that condition, use Int(exactly:) , eg: 如果值可能超出范围,并且您想要处理该条件,请使用Int(exactly:) ,例如:

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

In the specific case of rowids, using Int64 rather than Int was a deliberate API design choice, and truncating to Int could be a bug. 在rowid的特定情况下,使用Int64而不是Int是故意的API设计选择,截断到Int可能是一个错误。

It's a pain in the ass. 这是一个痛苦的屁股。 It's monumentally stupider than in Objective-C. 它比Objective-C更具有愚蠢性。 But here is how you do it. 但这是你如何做到的。

If you are using a UInt64 , you do it like this. 如果您使用的是UInt64 ,则可以这样做。

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

If you are using a UInt64? 如果您使用的是UInt64? , you do it like this. 你这样做。

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

Like I said, "It's monumentally stupider than in Objective-C." 就像我说的那样,“它比在Objective-C中更为愚蠢。”

Tested in Swift 4.2, Xcode 10.2.1 在Swift 4.2,Xcode 10.2.1中测试

As a matter of fact I've been working with this framework too, and basically I just used the opposite solution. 事实上,我也一直在使用这个框架,基本上我只是使用了相反的解决方案。 Whenever you see that types don't match just do 每当你看到那些类型不匹配时就这样做

Int64(yourInt) 

(tested with Xcode 7, Swift 2.0) (使用Xcode 7,Swift 2.0测试)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM