web-dev-qa-db-fra.com

Puis-je convertir Int64 directement dans Int?

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?

18
Renato Parreira

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
27
vacawama

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.

2
jedwidz

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)

0
René Blaser