Swift kennt im Wesentlichen dieselben Operatoren wie die meisten anderen Programmiersprachen — also etwa +, -, * und / für die Grundrechnungsarten, = für Zuweisungen, == und === für Vergleiche etc. Allerdings gibt es in Swift auch einige Besonderheiten, die einen genaueren Blick rechtfertigen. Vorweg ein Überblick:
Operator Bedeutung
------------ -----------------------------
(a, b) = (1, 2) Mehrfachzuweisung
a &+ b Addition ohne Überlaufkontrolle
a &- b Subtraktion ohne Überlaufkontrolle
a &* b Multiplikation ohne Überlaufkontrolle
a &/ b Division ohne Überlaufkontrolle
a &% b Restwert ohne Überlaufkontrolle
a ?? b Nil Coalescing
a ~= b Vergleichsoperator für `switch/case`
Mehrfachzuweisungen
Die Syntax a=b=3
als Kurzschreibweise von a=3
und b=3
ist in Swift nicht zulässig. Dafür können mehrere Variablen en bloc in einer Tupel-Schreibweise zugewiesen werden. Das ist auch praktisch für Funktionen, die nicht einen Wert zurückgeben soll, sondern mehrere Werte.
var (a, b, c) = (1, 7, 12)
Kein automatisches Casting
Alle Operatoren setzen voraus, dass links und rechts von ihnen jeweils gleichartige Datentypen verwendet werden!
var a = 3 // a ist eine Integer-Variable
var b = 1.7 // b ist ein Fließkommavariable
var c = a + b // Fehler, Int-Wert + Double-Wert nicht zulässig
Wenn Sie die Summe von a
plus b
ausrechnen möchten, müssen Sie explizit den Datentyp einer der beiden Operatoren anpassen. Int
rundet dabei immer ab, d.h. aus 1.7 wird 1.
var c1 = a + Int(b) // c1 = 4
var c2 = Double(a) + b // c2 = 4.7
Rechnen ohne Überlaufkontrolle
Swift führt (anders als beispielsweise Java!) standardmäßig bei bei allen Grundrechenarten eine Überlaufkontrolle durch. Wenn Sie sicher sind, dass kein Überlauf stattfinden kann, und Sie besonders effiziente Algorithmen programmieren möchten, verwenden Sie stattdessen die Operatoren &+
, &-
, &*
, &/
und &%
: Sie führen die Grundrechenarten ohne Überlaufkontrolle durch. Sollte allerdings doch ein Überlauf eintreten, dann ist das Ergebnis falsch!
var i = 10000000 // Integer
var result = i &* i &* i // falsches Ergebnis 3.875.820.019.684.212.736
Der Nil-Coalescing-Operator
Gewöhnliche Variablen dürfen in Swift nie null
sein. Das ist nur speziell gekennzeichneten Variablen vorbehalten, den sogenannten Optionals. Dabei folgt dem Datentyp ein Fragezeichen oder ein Ausrufezeichen. Diese Variablen können zwar auch nicht null
sein, aber sie dürfen den Swift-spezifischen Zustand nil
annehmen.
var x:Int? = 3 // x enthält eine ganze Zahl oder nil
var y:Int! = 4 // y enthält eine ganze Zahl oder nil
var z:Int = 5 // z enthält immer eine ganze Zahl
x = nil // ok
y = nil // ok
z = nil // nicht erlaubt
Der Unterschied zwischen x
und y
besteht darin, dass das Auspacken (Unwrapping) des eigentlichen Werts bei y
automatisch erfolgt, während es bei x
durch ein nachgestelltes Ausrufezeichen erzwungen werden muss. (Zu den weiteren Besonderheiten von Optionals plane ich demnächst einen eigenen Blog-Beitrag.)
Mit diesem Vorwissen kommen wir nun zum ebensoschwer aussprechlichen wie übersetzbaren Nil-Coalescing-Operator a ?? b
. Dabei handelt es sich um eine Kurzschreibweise des folgenden Ausdrucks:
a != nil ? a! : b
Wenn a
initialisiert ist, also nicht nil
ist, dann liefert a ?? b
den Wert von a
zurück, andernfalls den Wert von b
. Damit eignet sich b
zur Angabe eines Defaultwerts. Das Ausrufezeichen in a!
bewirkt das Auspacken (Unwrapping) des Optionals.
var i = x ?? -1 // der Datentyp von i ist Int
Vergleichsoperator für switch/case
Swift kennt mit ~=
einen Vergleichsoperator, der intern in switch-case
-Konstruktionen verwendet wird. Er bietet nur wenige Funktionen:
- Zwei Ausdrücke des gleichen Typs werden wie mit
==
verglichen. -
Außerdem kann ein durch den Range-Operator formulierters Intervall mit einer ganzen Zahl verglichen werden.
-2...2 ~= 1
isttrue
,1...10 ~= 12
liefertfalse
. Achten Sie darauf, dass Sie zuerst den Bereich und dann den Vergleichswert angeben müssen. Wenn Sie die Reihenfolge vertauschen, funktioniert der Operator nicht.
1...10 ~= 8 // true
1.7..<2.9 ~= 2.3 // true
"a"..."z" ~= "f" // true
"0"..."9" ~= "x" // false
Hinter den Kulissen kommt ~=
in switch
-Ausdrücken zum Einsatz, wo mit case
überprüft werden kann, ob sich ein ganzzahliger Ausdruck in einem vorgegebenen Bereich befindet:
let n = 12
switch n {
case (1...10):
println("Zahl zwischen 1 und 10")
case(11...20):
println("Zahl zwischen 11 und 20")
default:
println("Andere Zahl")
}
Range-Operatoren
In Swift gibt es zwei Operatoren, um Bereiche ganzer Zahlen auszudrücken:
- Der Closed-Range-Operator
a...b
beschreibt einen Bereich vona
bis inklusiveb
. -
Der Half-Open-Range-Operator
a..<b
beschreibt hingegen einen Bereich vona
bis exklusiveb
, entspricht alsoa...b-1
.
Mit den Range-Operatoren definierte Bereiche können in Schleifen, in switch-case
-Ausdrücken und mit dem vorhin vorgestellten Operator ~=
verarbeitet werden.
for i in 1...10 {
println(i)
}
In der folgenden Schreibweise können Sie Zahlenbereiche zur Initialisierung eines Integer-Arrays verwenden:
var ar = [Int](1...10) // entspricht var ar = [1, 2, ..., 10]
Mit map
können Sie auf einen Zahlenbereich direkt eine Funktion (Closure) anwenden:
(1...10).map { println($0) }
Bereiche (Range
s) können können nicht nur für Integer
-Zahlen gebildet werden, sondern auch für andere Datentypen, die dem Protokoll ForwardIndexType
entsprechen. Dazu zählen unter anderem auch String.Index
-Elemente zur Positionsangabe in Zeichenketten. Double
-Zahlen sind hingegen nicht geeignet, weil Sie das weder das ForwardIndexType
-Protokoll noch dessen successor
-Methode unterstützen.
Je nach Kontext können die Operatoren a...b
und a..<b
aber auch zur Formulierung eines Intervalls verwendet werden — z.B. als Vergleichsbasis für switch
bzw. für den oben beschriebenen Operator ~=
. In diesem Fall sind für a
und b
auch Fließkommazahlen oder einzelne Zeichen (Character
) erlaubt.
Operator Overloading, Definition neuer Operatoren
Swift ermöglicht es, vorhandene Operatoren durch eigene Implementierungen zu ersetzen sowie neue Operatoren zu definieren. Das ist vor allem dann zweckmäßig, wenn Sie zuerst eine eigene Klasse entwickeln und dann Objekte dieser Klasse vergleichen, aneinanderfügen etc. wollen.
struct Complex {
var re:Double, im:Double
init(re:Double, im:Double) {
self.re=re; self.im=im
}
}
// Multiplikation komplexer Zahlen
func * (left: Complex, right: Complex) -> Complex {
return Complex(re:left.re*right.re - left.im * right.im,
im:left.re*right.im+left.im*right.re)
}
var a = Complex(re: 2, im: 1) // 2 + i
var b = Complex(re: 1, im: 3) // 1 + 3i
var c = a * b // 3 + 4i
Links / Quellen
- Apple-Swift-Dokumentation
- Gute Operator-Übersicht von Mattt Thompson
- Beispiele für Operator Overloading
- Eigener Potenzier-Operator
- Eigener Operator für reguläre Ausdrücke
- Forward-Pipe-Operator
- ExSwift-Bibliothek mit diversen Spracherweiterungen, unter anderem mit Operatoren für reguläre Ausdrücke