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à.

  1. I modificatori prefix , infix e postfix sono utilizzati per avviare una dichiarazione personalizzata dell'operatore. I modificatori prefix e postfix dichiarano se l'operatore deve essere prima o dopo, rispettivamente, il valore su cui agisce. Tali operatori sono urnari, come 8 e 3++ ** , poiché possono agire solo su un obiettivo. L' infix dichiara un operatore binario che agisce sui due valori in cui è compreso, come 2+3 .

  2. 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 .

  3. 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.

3.0

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 ** .

3.0
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
    }
}
3.0

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
3.0
  • Il gruppo di precedenza DefaultPrecedence è superiore a TernaryPrecedence , ma non è ordinato con il resto degli operatori. Oltre a questo gruppo, il resto delle precedenze sono lineari.


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow