Bonjour les gars, je suis nouveau ici et en ce moment j'apprends Swift en codant des algorithmes sophistiqués, qui me viennent à l'esprit en lisant le livre Apples Swift.
J'essayais de compresser (automatiquement downcast) toute valeur IntegerType. Voici un petit extrait de mon code qui fonctionne presque bien sauf dans un cas:
switch signedValue
{
case Int64(Int8.min)...Int64(Int8.max): compressedValue = Int8(signedValue)
case (Int64(Int8.max) + 1)...Int64(UInt8.max): compressedValue = UInt8(signedValue)
case Int64(Int16.min)...Int64(Int16.max): compressedValue = Int16(signedValue)
case (Int64(Int16.max) + 1)...Int64(UInt16.max): compressedValue = UInt16(signedValue)
case Int64(Int32.min)...Int64(Int32.max): compressedValue = Int32(signedValue)
case (Int64(Int32.max) + 1)...Int64(UInt32.max): compressedValue = UInt32(signedValue)
case Int64(Int.min)...Int64(Int.max): compressedValue = Int(signedValue) // range bug #1 - workaround "..<"
default: compressedValue = signedValue
}
Supposons que signedValue est de type Int64 et que la valeur d'entrée est = 10_000_000_000. Cela entraînera une erreur d'exécution (dans Playground):
Execution was interrupted, reason: EXC_BAD_INSTRUCTION ...
Quelqu'un pourrait-il m'aider à comprendre ce qui se passe exactement ici. Il existe une solution de contournement pour ce problème. Au lieu de "...", je pourrais utiliser ".. <" mais ce n'est pas ainsi que la plage devrait être.
Réponses:
3 pour la réponse № 1Contrairement aux intervalles (qui ont deux saveurs, semi-ouverts ou fermés), Range
est seulement toujours à moitié ouvert. Alors quand tu écris 1...5
, la ...
la fonction incrémente l'argument de droite afin de créer une plage semi-ouverte 1..<6
.
La conséquence en est que vous ne pouvez pas avoir une plage qui couvre toute la longueur d’un type entier, car 1...Int.max
entraînera une tentative d'incrémentation Int.max
, et une erreur de débordement. Vous obtenez une erreur similaire avec let s = "hello"; let r = s.startIndex...s.endIndex
Cependant, tout n’est pas perdu, puisque vous ne devriez pas utiliser de plages de toute façon, c’est un travail pour ClosedInterval
. Depuis le ...
L'opérateur est utilisé pour les deux, et par défaut sur des plages (pour des raisons de priorité de surcharge), vous devez identifier explicitement le type:
let i64interval: ClosedInterval = Int64(Int64.min)...Int64(Int64.max)
switch signedValue {
// etc
case i64interval: compressedValue = Int(signedValue)
default: compressedValue = signedValue
}
3 pour la réponse № 2
Regarder La documentation pour le Range
Taper. Il contient la petite pépite d'informations suivante que je n'avais jamais remarquée auparavant:
si T a une valeur maximale, il peut servir de endIndex, mais ne peut jamais être contenu dans un Range.
T
, dans cette citation, est le type de valeur dans le Range
. Donc, si vous avez un Range
de Int
s, la valeur maximale du Int
ne peut pas être contenu dans le Range
.
C'est pourquoi cela fonctionne si vous mettez le ..<
là-dedans, au lieu de ...
.
Bonne question, au fait ...