Swift Language
Fortgeschrittene Operatoren
Suche…
Benutzerdefinierte Operatoren
Swift unterstützt die Erstellung von benutzerdefinierten Operatoren. Neue Operatoren werden auf globaler Ebene mit dem operator
Schlüsselwort deklariert.
Die Struktur des Operators besteht aus drei Teilen: Platzierung der Operanden, Rangfolge und Assoziativität.
Die Modifizierer
prefix
,infix
undpostfix
werden verwendet, um eine benutzerdefinierte Operatordeklaration zu starten. Dieprefix
undpostfix
Modifizierer legen fest, ob der Operator vor oder nach dem Wert stehen muss, auf den er wirkt. Solche Operatoren sind unüblich, wie8
und3++
** , da sie nur auf ein Ziel wirken können. Dasinfix
deklariert einen binären Operator, der auf die zwei Werte wirkt, zwischen denen es sich befindet, z. B.2+3
.Operatoren mit höherer Priorität werden zuerst berechnet. Die Standardpriorität des Operators ist nur höher als
?
...:
(ein Wert von 100 in Swift 2.x). Die Rangfolge der Standard-Swift-Operatoren finden Sie hier .Assoziativität definiert die Reihenfolge der Operationen zwischen Operatoren mit demselben Vorrang. Linke assoziative Operatoren werden von links nach rechts berechnet (Lesereihenfolge wie die meisten Operatoren), während rechte assoziative Operatoren von rechts nach links berechnen.
Ab Swift 3.0 würde man den Vorrang und die Assoziativität in einer Vorranggruppe anstelle des Operators selbst definieren, so dass mehrere Operatoren den gleichen Vorrang haben können, ohne sich auf die kryptischen Zahlen zu beziehen. Die Liste der Standard-Prioritätsgruppen ist unten aufgeführt .
Operatoren geben Werte basierend auf dem Berechnungscode zurück. Dieser Code fungiert als normale Funktion mit Parametern, die den Eingabetyp angeben, und das return
, das den berechneten Wert angibt, den der Operator zurückgibt.
Hier ist die Definition eines einfachen Exponentialoperators, da der Standard-Swift keinen Exponentialoperator hat.
import Foundation
infix operator ** { associativity left precedence 170 }
func ** (num: Double, power: Double) -> Double{
return pow(num, power)
}
Das infix
besagt, dass der Operator **
zwischen zwei Werten arbeitet, z. B. 9**2
. Da die Funktion die Assoziativität verlassen hat, wird 3**3**2
als (3**3)**2
berechnet. Der Vorrang von 170
ist höher als bei allen Standard-Swift-Operationen, was bedeutet, dass 3+2**4
trotz der linken Assoziativität von **
bis 19
berechnet wird.
import Foundation
infix operator **: BitwiseShiftPrecedence
func ** (num: Double, power: Double) -> Double {
return pow(num, power)
}
Anstatt die Priorität und die Assoziativität explizit anzugeben, können wir in Swift 3.0 die integrierte Prioritätsgruppe BitwiseShiftPrecedence verwenden, die die korrekten Werte angibt (wie <<
, >>
).
**: Das Inkrement und das Dekrement sind veraltet und werden in Swift 3 entfernt.
Überladen von + für Wörterbücher
Da es in Swift derzeit keine einfache Möglichkeit gibt, Wörterbücher zu kombinieren, kann es hilfreich sein, die Operatoren +
und +=
zu überladen , um diese Funktionalität mit Generics hinzuzufügen.
// 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
}
}
Ab Swift 3 sollte inout
vor dem Argumenttyp stehen.
func +=<K, V>(lhs: inout [K : V], rhs: [K : V]) { ... }
Verwendungsbeispiel:
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"]
Kommutative Operatoren
Fügen wir einen benutzerdefinierten Operator hinzu, um ein CGSize-Feld zu multiplizieren
func *(lhs: CGFloat, rhs: CGSize) -> CGSize{
let height = lhs*rhs.height
let width = lhs*rhs.width
return CGSize(width: width, height: height)
}
Das funktioniert jetzt
let sizeA = CGSize(height:100, width:200)
let sizeB = 1.1 * sizeA //=> (height: 110, width: 220)
Wenn wir versuchen, die Operation umgekehrt auszuführen, wird ein Fehler angezeigt
let sizeC = sizeB * 20 // ERROR
Aber es ist einfach genug hinzuzufügen:
func *(lhs: CGSize, rhs: CGFloat) -> CGSize{
return rhs*lhs
}
Jetzt ist der Operator kommutativ.
let sizeA = CGSize(height:100, width:200)
let sizeB = sizeA * 1.1 //=> (height: 110, width: 220)
Bitweise Operatoren
Swift Bitwise-Operatoren ermöglichen die Ausführung von Operationen in binärer Form von Zahlen. Sie können ein 0b
angeben, indem Sie der Zahl 0b
. 0b110
entspricht also der Binärzahl 110 (der Dezimalzahl 6). Jede 1 oder 0 ist ein Bit in der Nummer.
Bitweise NICHT ~
:
var number: UInt8 = 0b01101100
let newNumber = ~number
// newNumber is equal to 0b01101100
Hier wird jedes Bit in sein Gegenteil geändert. Durch die Deklaration der Zahl als explizit UInt8
sichergestellt, dass die Zahl positiv ist (damit wir uns in diesem Beispiel nicht mit Negativen befassen müssen) und dass diese nur 8 Bit beträgt. Wenn 0b01101100
ein größerer UInt wäre, gäbe es führende 0s, die in 1s umgewandelt würden und bei Inversion signifikant würden:
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
Bitweises AND &
:
var number = 0b0110
let newNumber = number & 0b1010
// newNumber is equal to 0b0010
Hier ist ein gegebenes Bit genau dann 1, wenn die Binärzahlen auf beiden Seiten des Operators &
eine 1 an dieser Bitposition enthalten.
- 0 & 0 -> 0
- 0 & 1 -> 0
- 1 & 1 -> 1
Bitweises ODER |
:
var number = 0b0110
let newNumber = number | 0b1000
// newNumber is equal to 0b1110
Hier ist ein gegebenes Bit genau dann 1, wenn sich die Binärzahl auf mindestens einer Seite von |
Operator enthielt an dieser Bitposition eine 1.
- 0 | 0 -> 0
- 0 | 1 -> 1
- 1 | 1 -> 1
Bitweises XOR (exklusives ODER) ^
:
var number = 0b0110
let newNumber = number ^ 0b1010
// newNumber is equal to 0b1100
Ein gegebenes Bit ist hier genau dann 1, wenn sich die Bits in dieser Position der beiden Operanden unterscheiden.
- 0 ^ 0 -> 0
- 0 ^ 1 -> 1
- 1 ^ 1 -> 0
Bei allen binären Operationen hat die Reihenfolge der Operanden keinen Einfluss auf das Ergebnis.
Überlaufoperatoren
Überlauf bezieht sich auf das, was passiert, wenn eine Operation dazu führen würde, dass eine Zahl größer oder kleiner als die festgelegte Anzahl von Bits für diese Anzahl ist.
Aufgrund der Funktionsweise der Binärarithmetik läuft die Anzahl der Bits zu groß, sobald eine Zahl für ihre Bits zu groß wird (für die Bitgröße), und zählt von dort aus weiter. Wenn eine Zahl zu klein wird, läuft sie auf die größtmögliche Anzahl (für ihre Bitgröße) unter und läuft weiter abwärts.
Da dieses Verhalten nicht oft gewünscht wird und zu schwerwiegenden Sicherheitsproblemen führen kann, werden die Swift-Rechenoperatoren +
, -
und *
Fehler auslösen, wenn ein Vorgang einen Überlauf oder Unterlauf verursacht. Um Überlauf und Unterlauf explizit zuzulassen, verwenden Sie stattdessen &+
, &-
und &*
.
var almostTooLarge = Int.max
almostTooLarge + 1 // not allowed
almostTooLarge &+ 1 // allowed, but result will be the value of Int.min
Vorrang vor Standard-Swift-Operatoren
Operatoren, die enger gebunden sind (höhere Priorität), werden zuerst aufgeführt.
Operatoren | Vorranggruppe (≥ 3,0) | Vorrang | Assoziativität |
---|---|---|---|
. | ∞ | links | |
? ! , ++ , -- , [] , () , {} | (postfix) | ||
! , ~ , + , - , ++ , -- | (Präfix) | ||
~> (schnell ≤2,3) | 255 | links | |
<< , >> | BitwiseShiftPrecedence | 160 | keiner |
* , / , % , & , &* | Multiplikationsvoraussetzung | 150 | links |
+ , - , | , ^ , &+ , &- | AdditionPrecedence | 140 | links |
... , ..< | RangeFormationPrecedence | 135 | keiner |
is as as? as! | CastingPrecedence | 132 | links |
?? | NilCoalescingPrecedence | 131 | Recht |
< , <= , > , >= , == === != , === !== , ~= | Vergleichspräferenz | 130 | keiner |
&& | LogicalConjunctionPrecedence | 120 | links |
|| | LogicalDisjunctionPrecedence | 110 | links |
DefaultPrecedence * | keiner | ||
? ... : | Ternäre Vorherrschaft | 100 | Recht |
= , += , -= , *= , /= , %= , <<= , >>= , &= , |= , ^= | AssignmentPrecedence | 90 | Richtig, Zuordnung |
-> | FunctionArrowPrecedence | Recht |
- Die
DefaultPrecedence
ist höher alsTernaryPrecedence
, ist jedoch bei den übrigen Operatoren ungeordnet. Abgesehen von dieser Gruppe sind die übrigen Prioritäten linear.
- Diese Tabelle ist auch in der API-Referenz von Apple zu finden
- Die eigentliche Definition der Vorranggruppen finden Sie im Quellcode von GitHub