ios - ¿Puedo lanzar Int64 directamente en Int?
swift sqlite.swift (3)
He estado usando SQLite.swift últimamente para construir mi base de datos de aplicaciones. Y estoy definiendo todas mis columnas INTEGER
con un tipo Int64
, como explica la documentación.
Pero de vez en cuando necesito que Int64
sea solo Int
. Así que mi pregunta es, si hago esto:
//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
}
¿Será correcto?
Por supuesto que lo probé. Y funciona, pero estaba leyendo esta pregunta en Stackoverflow
Y parece que podría tener un problema con dispositivos de 32 bits ...
Si esto está mal, ¿cómo puedo lanzar Int64
en Int
?
Convertir un Int64
a Int
al pasar el valor de Int64
al inicializador Int
siempre funcionará en una máquina de 64 bits y se bloqueará en una máquina de 32 bits si el número entero está fuera del rango Int32.min ... Int32.max
.
Por seguridad, use el init(truncatingIfNeeded:)
(anteriormente conocido como init(truncatingBitPattern:)
en versiones anteriores de Swift) para convertir el valor:
return Int(truncatingIfNeeded: rowid)
En una máquina de 64 bits, truncatingIfNeeded
no hará nada; solo obtendrás un Int
(que es el mismo tamaño que un Int64
todos modos).
En una máquina de 32 bits, esto eliminará los 32 bits superiores, pero si todos son ceros, no habrá perdido ningún dato. Entonces, siempre que su valor se ajuste a un Int
32 bits, puede hacerlo sin perder datos. Si su valor está fuera del rango Int32.min ... Int32.max
, esto cambiará el valor del Int64
en algo que se ajuste a un Int
32 bits, pero no se bloqueará.
Puedes ver cómo funciona esto en un parque infantil. Dado que Int
en un área de juegos es un Int
64 bits, puede usar explícitamente un Int32
para simular el comportamiento de un sistema de 32 bits.
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!
Actualización para Swift 3/4
Además de init(truncatingIfNeeded:)
que todavía funciona, Swift 3 introduce inicializadores failable para convertir de forma segura un tipo entero a otro. Al usar init?(exactly:)
puede pasar un tipo para inicializar otro, y devuelve nil
si la inicialización falla. El valor devuelto es un opcional que se debe desempaquetar de la forma habitual.
Por ejemplo:
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")
}
Esto le permite aplicar el operador de unión nula para proporcionar un valor predeterminado si la conversión falla:
// return 0 if rowid is too big to fit into an Int on this device
return Int(exactly: rowid) ?? 0
De hecho, también he estado trabajando con este marco, y básicamente he usado la solución opuesta. Cada vez que veas que los tipos no coinciden solo hazlo
Int64(yourInt)
(probado con Xcode 7, Swift 2.0)
Si está seguro de que el valor de Int64
se puede representar exactamente como un Int
, use Int(truncatingIfNeeded:)
, por ejemplo:
let salary: Int64 = 100000
let converted = Int(truncatingIfNeeded: salary)
Para compatibilidad con dispositivos de 32 bits, el rango para Int
es de -2147483648 a 2147483647, igual que Int32
. Los valores fuera de ese rango se descartarán silenciosamente sus bits de orden superior. Esto se traduce en basura, a menudo del signo opuesto.
Si el valor puede estar fuera del rango y desea controlar esa condición, use Int(exactly:)
, por ejemplo:
if let converted = Int(exactly: salary) {
// in range
... converted ...
} else {
// out-of-range
...
}
En el caso específico de los rowids, el uso de Int64
lugar de Int
fue una elección deliberada de diseño de API, y el truncado a Int
podría ser un error.