Swift Language
Operatori avanzati
Ricerca…
Operatori personalizzati
Swift supporta la creazione di operatori personalizzati. I nuovi operatori sono dichiarati a livello globale usando la parola chiave operator
.
La struttura dell'operatore è definita da tre parti: operando posizionamento, precedenza e associatività.
I modificatori
prefix
,infix
epostfix
sono utilizzati per avviare una dichiarazione personalizzata dell'operatore. I modificatoriprefix
epostfix
dichiarano se l'operatore deve essere prima o dopo, rispettivamente, il valore su cui agisce. Tali operatori sono urnari, come8
e3++
** , poiché possono agire solo su un obiettivo. L'infix
dichiara un operatore binario che agisce sui due valori in cui è compreso, come2+3
.Gli operatori con precedenza più alta vengono calcolati per primi. La precedenza dell'operatore predefinito è appena superiore a
?
...:
(un valore di 100 in Swift 2.x). La precedenza degli operatori Swift standard può essere trovata qui .Associatività definisce l'ordine delle operazioni tra operatori della stessa priorità. Gli operatori associativi di sinistra sono calcolati da sinistra a destra (ordine di lettura, come la maggior parte degli operatori), mentre gli operatori associativi di destra calcolano da destra a sinistra.
A partire da Swift 3.0, si definiscono la precedenza e l'associatività in un gruppo di precedenza anziché l'operatore stesso, in modo che più operatori possano condividere facilmente la stessa precedenza senza fare riferimento ai numeri criptici. L'elenco dei gruppi di precedenza standard è mostrato di seguito .
Gli operatori restituiscono valori basati sul codice di calcolo. Questo codice agisce come una funzione normale, con parametri che specificano il tipo di input e la parola chiave return
specifica il valore calcolato restituito dall'operatore.
Ecco la definizione di un semplice operatore esponenziale, poiché lo standard Swift non ha un operatore esponenziale.
import Foundation
infix operator ** { associativity left precedence 170 }
func ** (num: Double, power: Double) -> Double{
return pow(num, power)
}
L' infix
dice che l'operatore **
lavora tra due valori, come 9**2
. Poiché la funzione ha lasciato l'associatività, 3**3**2
viene calcolata come (3**3)**2
. La precedenza di 170
è superiore a tutte le operazioni Swift standard, il che significa che 3+2**4
calcola a 19
, nonostante l'associatività a sinistra di **
.
import Foundation
infix operator **: BitwiseShiftPrecedence
func ** (num: Double, power: Double) -> Double {
return pow(num, power)
}
Invece di specificare esplicitamente la precedenza e l'associatività, su Swift 3.0 potremmo usare il gruppo di precedenza predefinito BitwiseShiftPrecedence che fornisce i valori corretti (come <<
, >>
).
**: l'incremento e il decremento sono deprecati e verranno rimossi in Swift 3.
Sovraccarico + per dizionari
Poiché attualmente non esiste un modo semplice per combinare i dizionari in Swift, può essere utile sovraccaricare gli operatori +
e +=
per aggiungere questa funzionalità utilizzando i generici .
// 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
}
}
A partire da Swift 3, inout
deve essere posizionato prima del tipo di argomento.
func +=<K, V>(lhs: inout [K : V], rhs: [K : V]) { ... }
Esempio di utilizzo:
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"]
Operatori commutativi
Aggiungiamo un operatore personalizzato per moltiplicare un CGSize
func *(lhs: CGFloat, rhs: CGSize) -> CGSize{
let height = lhs*rhs.height
let width = lhs*rhs.width
return CGSize(width: width, height: height)
}
Ora questo funziona
let sizeA = CGSize(height:100, width:200)
let sizeB = 1.1 * sizeA //=> (height: 110, width: 220)
Ma se proviamo a fare l'operazione al contrario, otteniamo un errore
let sizeC = sizeB * 20 // ERROR
Ma è abbastanza semplice aggiungere:
func *(lhs: CGSize, rhs: CGFloat) -> CGSize{
return rhs*lhs
}
Ora l'operatore è commutativo.
let sizeA = CGSize(height:100, width:200)
let sizeB = sizeA * 1.1 //=> (height: 110, width: 220)
Operatori bit a bit
Swift Operatori bit a bit consentono di eseguire operazioni sulla forma binaria di numeri. È possibile specificare un valore letterale binario prefissando il numero con 0b
, quindi per esempio 0b110
equivale al numero binario 110 (il numero decimale 6). Ogni 1 o 0 è un po 'nel numero.
Bitwise NOT ~
:
var number: UInt8 = 0b01101100
let newNumber = ~number
// newNumber is equal to 0b01101100
Qui, ogni bit viene cambiato nel suo opposto. Dichiarare il numero come esplicitamente UInt8
assicura che il numero sia positivo (in modo che non ci sia da trattare con i negativi nell'esempio) e che sia solo 8 bit. Se 0b01101100
fosse un UInt più grande, ci sarebbero degli 0 iniziali che verrebbero convertiti in 1 e diventerebbero significativi in caso di inversione:
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
AND bit a bit &
:
var number = 0b0110
let newNumber = number & 0b1010
// newNumber is equal to 0b0010
Qui, un dato bit sarà 1 se e solo se i numeri binari su entrambi i lati dell'operatore &
contenessero un 1 in quella posizione di bit.
- 0 e 0 -> 0
- 0 & 1 -> 0
- 1 & 1 -> 1
Bitwise OR |
:
var number = 0b0110
let newNumber = number | 0b1000
// newNumber is equal to 0b1110
Qui, un dato bit sarà 1 se e solo se il numero binario su almeno un lato del |
l'operatore conteneva un 1 in quella posizione di bit.
- 0 | 0 -> 0
- 0 | 1 -> 1
- 1 | 1 -> 1
XOR bit a bit (OR esclusivo) ^
:
var number = 0b0110
let newNumber = number ^ 0b1010
// newNumber is equal to 0b1100
Qui, un dato bit sarà 1 se e solo se i bit in quella posizione dei due operandi sono diversi.
- 0 ^ 0 -> 0
- 0 ^ 1 -> 1
- 1 ^ 1 -> 0
Per tutte le operazioni binarie, l'ordine degli operandi non fa differenza sul risultato.
Operatori di overflow
L'overflow si riferisce a ciò che accade quando un'operazione determina un numero che può essere maggiore o minore della quantità di bit designata per quel numero.
A causa del modo in cui funziona l'aritmetica binaria, dopo che un numero diventa troppo grande per i suoi bit, il numero trabocca al numero più piccolo possibile (per la dimensione del bit) e quindi continua a contare da lì. Allo stesso modo, quando un numero diventa troppo piccolo, esso porta fino al numero più grande possibile (per la sua dimensione di bit) e continua il conto alla rovescia da lì.
Poiché questo comportamento non è spesso desiderato e può portare a seri problemi di sicurezza, gli operatori aritmetici Swift +
, -
e *
generano errori quando un'operazione provoca un overflow o un underflow. Per consentire esplicitamente overflow e underflow, utilizza invece &+
, &-
, e &*
.
var almostTooLarge = Int.max
almostTooLarge + 1 // not allowed
almostTooLarge &+ 1 // allowed, but result will be the value of Int.min
Precedenza degli operatori Swift standard
Gli operatori che vincolano più strettamente (precedenza più alta) sono elencati per primi.
operatori | Gruppo di precedenza (≥3,0) | Precedenza | Associatività |
---|---|---|---|
. | ∞ | sinistra | |
? , ! , ++ , -- , [] , () , {} | (Postfix) | ||
! , ~ , + , - , ++ , -- | (prefisso) | ||
~> (rapido ≤2.3) | 255 | sinistra | |
<< , >> | BitwiseShiftPrecedence | 160 | nessuna |
* , / , % , & , &* | MultiplicationPrecedence | 150 | sinistra |
+ , - , | , ^ , &+ , &- | AdditionPrecedence | 140 | sinistra |
... , ..< | RangeFormationPrecedence | 135 | nessuna |
is , as , as? , as! | CastingPrecedence | 132 | sinistra |
?? | NilCoalescingPrecedence | 131 | destra |
< , <= , > , >= , == != , === !== , ~= | ComparisonPrecedence | 130 | nessuna |
&& | LogicalConjunctionPrecedence | 120 | sinistra |
|| | LogicalDisjunctionPrecedence | 110 | sinistra |
DefaultPrecedence * | nessuna | ||
? ... : | TernaryPrecedence | 100 | destra |
= , += , -= , *= , /= , %= , <<= , >>= , &= , |= , ^= | AssignmentPrecedence | 90 | giusto, incarico |
-> | FunctionArrowPrecedence | destra |
- Il gruppo di precedenza
DefaultPrecedence
è superiore aTernaryPrecedence
, ma non è ordinato con il resto degli operatori. Oltre a questo gruppo, il resto delle precedenze sono lineari.
- Questa tabella può essere trovata anche sul riferimento API di Apple
- La definizione attuale dei gruppi di precedenza può essere trovata nel codice sorgente su GitHub