Historie der Frage:
Schattenbildung (Shadowing) ist das Phänomen, bei dem eine Variable mit demselben Namen im inneren Sichtbereich deklariert wird, wodurch die Variable im äußeren Sichtbereich überschattet wird. In früheren Versionen von Swift war der Compiler nicht streng in Bezug auf Shadowing, aber mit der Komplexität des Sprachmodells wurde die explizite Identifizierung solcher Fälle zur Vermeidung von Bugs obligatorisch.
Problem:
Shadowing erschwert die Wartung des Codes und führt zu schwer fassbaren Fehlern – die versehentliche Deklaration einer Variable mit demselben Namen kann dazu führen, dass auf die falsche Variable zugegriffen wird, die der Entwickler erwartet. Dies ist besonders kritisch bei der Übergabe von Variablen per Referenz und innerhalb von Schleifen oder Closures – oftmals treten die Fehler erst zur Laufzeit auf.
Lösung:
Swift erlaubt das Shadowing von Variablen, aber es wird empfohlen, das Überschatten wichtiger Variablen/Eigenschaften zu vermeiden, unterschiedliche Namen zu verwenden oder explizite self/this-Referenzen zu nutzen. Besonders in den Initialisierern von struct/class wird empfohlen, self zu verwenden, um zwischen Mitglied und Parameter zu unterscheiden:
Beispielcode:
struct User { let name: String init(name: String) { self.name = name // self garantier die Eindeutigkeit der Zuweisung } }
Schlüsselmerkmale:
Was passiert bei Shadowing in Schleifen und Closures?
Wenn eine Variable innerhalb eines Closures mit demselben Namen wie im äußeren Kontext deklariert wird, verbirgt das Shadowing die äußere Variable. Dies kann manchmal unerwartetes Verhalten erzeugen, insbesondere bei Mehrfachverarbeitungen.
let value = 10 let closure = { let value = 20; print(value) } closure() // 20 print(value) // 10
Kann man in einem Sichtbereich eine Konstante und eine Variable mit demselben Namen deklarieren?
Nein. Swift erlaubt es nicht, var und let für denselben Namen innerhalb eines Sichtbereichs zu haben:
let x = 5 var x = 10 // Fehler: Ungültige Neueinführung von 'x'
Wie vermeidet man Verwirrung mit dem Shadowing von Klassen-Eigenschaften bei Vererbung?
Wenn eine Unterklasse eine Eigenschaft mit dem Namen der Elterneigenschaft deklariert, tritt Shadowing auf. Beim Zugriff über super oder self wird jedoch die entsprechende Eigenschaft ausgewählt. Es ist besser, ohne Not keine identischen Namen zu verwenden.
In der Klasse Account hat einer der Entwickler versehentlich die Variable balance als Namen für einen Funktionsparameter verwendet und innerhalb der Funktion erneut let balance = ... verwendet. Aufgrund von Shadowing wurde die Berechnung nicht mit dem richtigen Wert durchgeführt und die Funktion gab ein falsches Ergebnis zurück, was erst in einer späten Testphase auffiel.
Vorteile:
Nachteile:
Das gesamte Team hat sich darauf geeinigt, Präfixe (zum Beispiel inputBalance) zu verwenden oder immer self für Verweise auf Eigenschaften zu verwenden. Infolgedessen sind Fehler mit Shadowing nahezu verschwunden und die Wartung des Codes hat sich vereinfacht.
Vorteile:
Nachteile: