J'utilise SQLite.Swift récemment pour construire ma base de données d'applications . Et je définis toutes mes colonnes INTEGER
avec un type Int64
, comme l'explique la documentation.
Mais de temps en temps, j'ai besoin de ce Int64
pour être juste Int
. Donc ma question est, si je fais ceci:
//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
}
Sera-ce correct?
Bien sûr je l'ai testé. Et ça marche, mais je lisais cette question dans Stackoverflow
Et il semble que je puisse avoir un problème avec les appareils 32 bits ...
Si cela est faux, comment puis-je convertir Int64
en Int
?
La conversion d'un Int64
en Int
en transmettant la valeur Int64
à l'initialiseur Int
fonctionnera toujours sur un ordinateur 64 bits et se bloquera sur un ordinateur 32 bits si l'entier est en dehors de la plage Int32.min ... Int32.max
.
Pour des raisons de sécurité, utilisez l'initialiseur init(truncatingIfNeeded:)
(anciennement init(truncatingBitPattern:)
dans les versions précédentes de Swift) pour convertir la valeur:
return Int(truncatingIfNeeded: rowid)
Sur une machine 64 bits, la truncatingIfNeeded
ne fera rien; vous obtiendrez simplement une Int
(qui a la même taille qu'un Int64
de toute façon).
Sur une machine 32 bits, les 32 bits supérieurs seront éliminés, mais si ce sont des zéros, vous n’a perdu aucune donnée. Donc, tant que votre valeur tiendra dans une Int
32 bits, vous pouvez le faire sans perdre de données. Si votre valeur se situe en dehors de la plage Int32.min ... Int32.max
, la valeur du Int64
sera remplacée par un élément qui correspond à une Int
32 bits, mais elle ne plantera pas.
Vous pouvez voir comment cela fonctionne dans un terrain de jeu. Étant donné que Int
dans un terrain de jeu est une Int
64 bits, vous pouvez utiliser explicitement un Int32
pour simuler le comportement d'un système 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!
Mise à jour pour Swift 3/4
En plus de init(truncatingIfNeeded:)
qui fonctionne toujours, Swift 3 introduit les initialiseurs disponibles pour convertir en toute sécurité un type d’entier en un autre. En utilisant init?(exactly:)
, vous pouvez passer un type pour en initialiser un autre et il renvoie nil
si l'initialisation échoue. La valeur renvoyée est une option qui doit être décompressée de la manière habituelle.
Par exemple:
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")
}
Cela vous permet d'appliquer l'opérateur de coalescence nil pour fournir une valeur par défaut en cas d'échec de la conversion:
// return 0 if rowid is too big to fit into an Int on this device
return Int(exactly: rowid) ?? 0
Si vous êtes sûr que la valeur Int64
peut être représentée exactement par un Int
, utilisez Int(truncatingIfNeeded:)
, par exemple:
let salary: Int64 = 100000
let converted = Int(truncatingIfNeeded: salary)
Pour assurer la compatibilité avec les périphériques 32 bits, la plage de Int
va de -2147483648 à 2147483647, identique à celle de Int32
. Les valeurs situées en dehors de cette plage verront leurs bits de poids fort ignorés. Cela entraîne des déchets, souvent du signe opposé.
Si la valeur est peut-être en dehors de la plage et que vous souhaitez gérer cette condition, utilisez Int(exactly:)
, par exemple:
if let converted = Int(exactly: salary) {
// in range
... converted ...
} else {
// out-of-range
...
}
Dans le cas spécifique de rowid, utiliser Int64
plutôt que Int
était un choix de conception d'API délibéré et le fait de tronquer à Int
pourrait être un bogue.
En fait, j’ai également travaillé avec ce cadre et j’ai utilisé la solution inverse. Chaque fois que vous voyez que les types ne correspondent pas, faites simplement
Int64(yourInt)
(testé avec Xcode 7, Swift 2.0)