/ / Swift range bug avec switch-statement - swift, casting, switch-statement, range, downcast

Swift range bug avec switch-statement - rapide, casting, switch-statement, range, downcast

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 № 1

Contrairement 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 Ints, 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 ...