Swift Language
Opérateurs avancés
Recherche…
Opérateurs personnalisés
Swift prend en charge la création d'opérateurs personnalisés. Les nouveaux opérateurs sont déclarés au niveau global en utilisant le mot-clé operator
.
La structure de l'opérateur est définie en trois parties: placement de l'opérande, priorité et associativité.
Les modificateurs de
prefix
,infix
etpostfix
sont utilisés pour lancer une déclaration d'opérateur personnalisée. Les modificateurs deprefix
et depostfix
déclarent si l'opérateur doit être avant ou après, respectivement, la valeur sur laquelle il agit. Ces opérateurs sont urinaires, comme8
et3++
** , car ils ne peuvent agir que sur une seule cible. L'infix
déclare un opérateur binaire, qui agit sur les deux valeurs entre lesquelles il se trouve, telles que2+3
.Les opérateurs avec une priorité supérieure sont calculés en premier. La priorité de l'opérateur par défaut est juste supérieure à
?
...:
(une valeur de 100 dans Swift 2.x). La priorité des opérateurs Swift standard peut être trouvée ici .L'associativité définit l'ordre des opérations entre opérateurs de même priorité. Les opérateurs associatifs de gauche sont calculés de gauche à droite (ordre de lecture, comme la plupart des opérateurs), tandis que les opérateurs associatifs de droite calculent de droite à gauche.
À partir de Swift 3.0, on définirait la priorité et l’associativité dans un groupe de priorité au lieu de l’opérateur lui-même, de sorte que plusieurs opérateurs puissent facilement partager la même priorité sans faire référence aux nombres cryptés. La liste des groupes de priorité standard est indiquée ci - dessous .
Les opérateurs renvoient des valeurs en fonction du code de calcul. Ce code agit comme une fonction normale, avec des paramètres spécifiant le type d'entrée et le mot-clé de return
spécifiant la valeur calculée que l'opérateur retourne.
Voici la définition d'un opérateur exponentiel simple, car Swift standard n'a pas d'opérateur exponentiel.
import Foundation
infix operator ** { associativity left precedence 170 }
func ** (num: Double, power: Double) -> Double{
return pow(num, power)
}
L' infix
indique que l'opérateur **
travaille entre deux valeurs, telles que 9**2
. Comme la fonction a laissé une associativité, 3**3**2
est calculé comme suit: (3**3)**2
. La priorité de 170
est supérieure à toutes les opérations Swift standard, ce qui signifie que 3+2**4
calcule à 19
, malgré l’associativité de gauche de **
.
import Foundation
infix operator **: BitwiseShiftPrecedence
func ** (num: Double, power: Double) -> Double {
return pow(num, power)
}
Au lieu de spécifier explicitement la préséance et l'associativité, sur Swift 3.0, nous pourrions utiliser le groupe de priorité intégré BitwiseShiftPrecedence qui donne les valeurs correctes (identiques à <<
, >>
).
**: L'incrémentation et la décrémentation sont obsolètes et seront supprimées dans Swift 3.
Surcharge + pour les dictionnaires
Comme il n'existe actuellement aucun moyen simple de combiner des dictionnaires dans Swift, il peut être utile de surcharger les opérateurs +
et +=
pour ajouter cette fonctionnalité à l'aide de génériques .
// Combines two dictionaries together. If both dictionaries contain
// the same key, the value of the right hand side dictionary is used.
func +<K, V>(lhs: [K : V], rhs: [K : V]) -> [K : V] {
var combined = lhs
for (key, value) in rhs {
combined[key] = value
}
return combined
}
// The mutable variant of the + overload, allowing a dictionary
// to be appended to 'in-place'.
func +=<K, V>(inout lhs: [K : V], rhs: [K : V]) {
for (key, value) in rhs {
lhs[key] = value
}
}
À partir de Swift 3, inout
doit être placé avant le type d'argument.
func +=<K, V>(lhs: inout [K : V], rhs: [K : V]) { ... }
Exemple d'utilisation:
let firstDict = ["hello" : "world"]
let secondDict = ["world" : "hello"]
var thirdDict = firstDict + secondDict // ["hello": "world", "world": "hello"]
thirdDict += ["hello":"bar", "baz":"qux"] // ["hello": "bar", "baz": "qux", "world": "hello"]
Opérateurs de communication
Ajoutons un opérateur personnalisé pour multiplier un CGSize
func *(lhs: CGFloat, rhs: CGSize) -> CGSize{
let height = lhs*rhs.height
let width = lhs*rhs.width
return CGSize(width: width, height: height)
}
Maintenant cela fonctionne
let sizeA = CGSize(height:100, width:200)
let sizeB = 1.1 * sizeA //=> (height: 110, width: 220)
Mais si nous essayons de faire l'opération en sens inverse, nous obtenons une erreur
let sizeC = sizeB * 20 // ERROR
Mais c'est assez simple d'ajouter:
func *(lhs: CGSize, rhs: CGFloat) -> CGSize{
return rhs*lhs
}
Maintenant, l'opérateur est commutatif.
let sizeA = CGSize(height:100, width:200)
let sizeB = sizeA * 1.1 //=> (height: 110, width: 220)
Opérateurs sur les bits
Les opérateurs Swift Bitwise vous permettent d'effectuer des opérations sur la forme binaire des nombres. Vous pouvez spécifier un littéral binaire en préfixant le nombre avec 0b
. Par exemple, 0b110
équivaut au nombre binaire 110 (nombre décimal 6). Chaque 1 ou 0 est un peu dans le nombre.
Bitwise NOT ~
:
var number: UInt8 = 0b01101100
let newNumber = ~number
// newNumber is equal to 0b01101100
Ici, chaque bit se transforme en son contraire. Déclarer explicitement le nombre UInt8
garantit que le nombre est positif (pour que nous n'ayons pas à traiter de négatifs dans l'exemple) et qu'il ne s'agisse que de 8 bits. Si 0b01101100
était un UInt plus grand, il y aurait des 0 qui seraient convertis en 1 et deviendraient significatifs lors de l'inversion:
var number: UInt16 = 0b01101100
// number equals 0b0000000001101100
// the 0s are not significant
let newNumber = ~number
// newNumber equals 0b1111111110010011
// the 1s are now significant
- 0 à> 1
- 1 -> 0
Bitwise AND &
:
var number = 0b0110
let newNumber = number & 0b1010
// newNumber is equal to 0b0010
Ici, un bit donné sera 1 si et seulement si les nombres binaires des deux côtés de l'opérateur &
contenaient un 1 à cet endroit du bit.
- 0 & 0 -> 0
- 0 & 1 -> 0
- 1 & 1 -> 1
Bit à bit OU |
:
var number = 0b0110
let newNumber = number | 0b1000
// newNumber is equal to 0b1110
Ici, un bit donné sera 1 si et seulement si le nombre binaire sur au moins un côté du |
l'opérateur contenait un 1 à cet endroit du bit.
- 0 | 0 -> 0
- 0 | 1 -> 1
- 1 | 1 -> 1
Bit à bit XOR (OU exclusif) ^
:
var number = 0b0110
let newNumber = number ^ 0b1010
// newNumber is equal to 0b1100
Ici, un bit donné sera 1 si et seulement si les bits dans cette position des deux opérandes sont différents.
- 0 ^ 0 -> 0
- 0 ^ 1 -> 1
- 1 ^ 1 -> 0
Pour toutes les opérations binaires, l'ordre des opérandes ne fait aucune différence sur le résultat.
Opérateurs de débordement
Le dépassement de capacité se rapporte à ce qui se produit lorsqu'une opération aboutit à un nombre supérieur ou inférieur à la quantité de bits spécifiée pour ce numéro.
En raison de la façon dont fonctionne l'arithmétique binaire, après qu'un nombre soit devenu trop grand pour ses bits, le nombre déborde jusqu'au plus petit nombre possible (pour la taille du bit) et continue ensuite à compter. De la même manière, lorsqu'un nombre devient trop petit, il débouche sur le plus grand nombre possible (pour sa taille en bits) et continue à décompter à partir de là.
Étant donné que ce comportement n'est pas souvent souhaité et peut entraîner de graves problèmes de sécurité, les opérateurs arithmétiques Swift +
, -
et *
émet des erreurs lorsqu'une opération provoque un débordement ou un débordement. Pour autoriser explicitement le dépassement et le sous-dépassement, utilisez plutôt &+
, &-
et &*
.
var almostTooLarge = Int.max
almostTooLarge + 1 // not allowed
almostTooLarge &+ 1 // allowed, but result will be the value of Int.min
Préséance des opérateurs Swift standard
Les opérateurs liés plus fortement (priorité supérieure) sont listés en premier.
Les opérateurs | Groupe de préséance (≥3.0) | Priorité | Associativité |
---|---|---|---|
. | ∞ | la gauche | |
? , ! , ++ , -- , [] , () , {} | (postfix) | ||
! , ~ , + , - , ++ , -- | (préfixe) | ||
~> (swift ≤2.3) | 255 | la gauche | |
<< , >> | BitwiseShiftPrecedence | 160 | aucun |
* , / , % , & , &* | MultiplicationPrecedence | 150 | la gauche |
+ , - , | , ^ , &+ , &- | AdditionPrecedence | 140 | la gauche |
... , ..< | RangeFormationPrecedence | 135 | aucun |
is , as , as? , as! | CastingPrecedence | 132 | la gauche |
?? | NilCoalescingPrecedence | 131 | droite |
< , <= , > , >= , == != , === !== , ~= | ComparaisonPrécédence | 130 | aucun |
&& | LogicalConjunctionPrecedence | 120 | la gauche |
|| | LogicalDisjunctionPrecedence | 110 | la gauche |
DefaultPrecedence * | aucun | ||
? ... : | TernaryPrecedence | 100 | droite |
= , += , -= , *= , /= , %= , <<= , >>= , &= , |= , ^= | AssignmentPrecedence | 90 | droit, cession |
-> | FunctionArrowPrecedence | droite |
- Le groupe de priorité
DefaultPrecedence
est supérieur àTernaryPrecedence
, mais il n'est pas ordonné avec le reste des opérateurs. Outre ce groupe, les autres priorités sont linéaires.
- Cette table se trouve également sur la référence API d'Apple
- La définition réelle des groupes de priorité peut être trouvée dans le code source sur GitHub.