Il s'agit d'une question sur le style de programmation dans Swift, en particulier Int
vs UInt
.
Le Swift Programming Language Guide conseille aux programmeurs d'utiliser le type d'entier signé générique Int
même lorsque les variables sont connues pour être non négatives. De le guide :
Utilisez UInt uniquement lorsque vous avez spécifiquement besoin d'un type d'entier non signé avec la même taille que la taille Word native de la plate-forme. Si ce n'est pas le cas, Int est préféré, même lorsque les valeurs à stocker sont connues pour être non négatives. Une utilisation cohérente de Int pour les valeurs entières facilite l'interopérabilité du code, évite la nécessité de convertir entre différents types de nombres et correspond à l'inférence de type entier, comme décrit dans Sécurité du type et Inférence de type.
Cependant, UInt
sera non signé 32 bits sur les architectures 32 bits et 64 bits non signé sur les architectures 64 bits, donc il n'y a aucun avantage en termes de performances à utiliser Int
sur UInt
.
En revanche, le guide Swift donne un exemple ultérieur:
soit age = -3
assert (age> = 0, "L'âge d'une personne ne peut pas être inférieur à zéro")
// ceci provoque le déclenchement de l'assertion, car l'âge n'est pas> = 0
Ici, un problème runtime pourrait être détecté à compilation si le code avait été écrit comme suit:
let age:UInt = -3
// this causes a compiler error because -3 is negative
Il existe de nombreux autres cas (par exemple tout ce qui va indexer une collection) où l'utilisation d'un UInt
intercepterait des problèmes au moment de la compilation plutôt qu'à l'exécution.
Donc, la question: est le conseil dans le son du guide du langage de programmation Swift, et profitez des avantages de l'utilisation de Int
"même lorsque les valeurs à stocker sont connues pour être non négatif "l'emportent sur les avantages en termes de sécurité de l'utilisation de UInt
?
Note supplémentaire: Après avoir utilisé Swift pendant quelques semaines, il est clair que pour l'interopérabilité avec Cocoa UInt
est requis. Par exemple, le framework AVFoundation
utilise des entiers non signés partout où un "nombre" est requis (nombre d'échantillons/trames/canaux, etc.). La conversion de ces valeurs en Int
pourrait entraîner de graves bogues où les valeurs sont supérieures à Int.max
Je ne pense pas que l'utilisation d'UInt soit aussi sûre que vous le pensez. Comme vous l'avez noté:
let age:UInt = -3
entraîne une erreur de compilation. J'ai aussi essayé:
let myAge:Int = 1
let age:UInt = UInt(myAge) - 3
ce qui a également entraîné une erreur de compilation. Cependant, les scénarios suivants (à mon avis, beaucoup plus courants dans les programmes réels) n'avaient pas d'erreur de compilation, mais ont en fait entraîné des erreurs d'exécution de EXC_BAD_INSTRUCTION
:
func sub10(num: Int) -> UInt {
return UInt(num - 10) //Runtime error when num < 10
}
sub10(4)
aussi bien que:
class A {
var aboveZero:UInt
init() { aboveZero = 1 }
}
let a = A()
a.aboveZero = a.aboveZero - 10 //Runtime error
Si ceux-ci étaient simples Int
s, au lieu de planter, vous pourriez ajouter du code pour vérifier vos conditions:
if a.aboveZero > 0 {
//Do your thing
} else {
//Handle bad data
}
Je pourrais même aller jusqu'à assimiler leurs conseils contre l’utilisation de UInt
s à leurs conseils contre l’utilisation d’options implicitement déballées: ne le faites que si vous êtes certain que vous n’obtiendrez aucun négatif, sinon vous obtenir des erreurs d'exécution (sauf dans le cas le plus simple).
Il dit dans votre question .. "Une utilisation cohérente d'Int pour les valeurs entières facilite l'interopérabilité du code, évite la nécessité de convertir entre différents types de nombres et correspond à l'inférence de type entier, comme décrit dans Sécurité du type et Inférence de type."
Cela évite des problèmes tels que l'attribution d'un Int à un UInt. Les valeurs Int négatives affectées aux UInts entraînent de grandes valeurs au lieu de la valeur négative voulue. La représentation binaire des deux ne différencie pas un type de l'autre.
En outre, les deux sont des classes, l'une ne descendant pas de l'autre. Les classes construites reçoivent des Ints ne peuvent pas recevoir des UInts sans surcharge, ce qui signifie que la conversion entre les deux serait une tâche courante lorsque des UInts sont utilisés lorsque la plupart du framework reçoit des Ints. La conversion entre les deux peut également devenir une tâche non équivalente.
Les deux paragraphes précédents parlent d '"interopérabilité" et de "conversion entre différents types de numéros". Problèmes qui sont évités si les UInts ne sont pas utilisés.