Der Subscript-Mechanismus in Swift wurde 2014 mit der Einführung der Sprache eingeführt und dient dazu, auf Daten von Sammlungen mit einer bequemeren Syntax zuzugreifen. Subscripts ermöglichen den Zugriff auf Elemente von Arrays, Dictionaries und anderen Sammlungen über eckige Klammern. Modernes Swift erlaubt die Erstellung benutzerdefinierter Subscripts für benutzerdefinierte Typen, wodurch die API intuitiv verständlich ist, ähnlich wie bei den Standarddatenstrukturen.
Problem: Früher sahen Zugriffsmethoden umständlicher aus (zum Beispiel über .getElement(at:)), während Subscript die Interaktion mit dem Typ prägnant gestaltet. Eine fehlerhafte Implementierung kann jedoch zu suboptimalem Code oder Zugriffsfehlern außerhalb der Sammlung führen.
Lösung: Für die Implementierung von Subscript wird das Schlüsselwort subscript verwendet, gefolgt von den Parametern und dem Rückgabewert. Subscript kann entweder nur zum Lesen oder sowohl zum Lesen als auch zum Schreiben verwendet werden. Darüber hinaus können Subscripts für verschiedene Parameter überladen werden.
Beispielcode:
struct Matrix { let rows: Int let columns: Int var grid: [Double] init(rows: Int, columns: Int) { self.rows = rows self.columns = columns self.grid = Array(repeating: 0.0, count: rows * columns) } subscript(row: Int, column: Int) -> Double { get { assert(row >= 0 && row < rows && column >= 0 && column < columns, "Index außerhalb des Bereichs") return grid[(row * columns) + column] } set { assert(row >= 0 && row < rows && column >= 0 && column < columns, "Index außerhalb des Bereichs") grid[(row * columns) + column] = newValue } } } var matrix = Matrix(rows: 2, columns: 2) matrix[0, 1] = 3.14 print(matrix[0, 1]) // 3.14
Wichtige Merkmale:
Kann man Subscript nur zum Lesen festlegen? Oder muss Subscript immer get und set haben?
Subscript kann nur zum Lesen (nur get) sein, wenn in der Implementierung kein set vorhanden ist. Es ist nicht erforderlich, beide Zugriffsmethoden zu implementieren, was analog zu Eigenschaften ist.
Beispielcode:
subscript(index: Int) -> Int { get { return index * 2 } }
Kann man veränderliche Parameter über inout in Subscript übergeben?
Nein, Subscript unterstützt keine inout-Parameter in der Signatur. Alle Parameter von Subscripts werden im Körper der Zugriffsmethoden als let-Konstanten behandelt.
Können Subscripts optionale Typen zurückgeben?
Ja, Subscripts können optionale Werte zurückgeben, was nützlich ist, um beispielsweise sicher auf Elemente einer Sammlung zuzugreifen, ohne das Risiko eines Array-Überlaufs.
Beispielcode:
extension Array { subscript(safe index: Int) -> Element? { return indices.contains(index) ? self[index] : nil } }
Implementierung von Subscript ohne Überprüfung auf Grenzwerte für den zusammengesetzten Typ Matrix, was zu einem Absturz der Anwendung bei Indexfehlern führt.
Vorteile:
Nachteile:
Eine optionale Version von Subscript wurde hinzugefügt, um eine sichere Indizierung und Fehlerbehandlung zu ermöglichen, wodurch die API klar und geschützt wird.
Vorteile:
Nachteile: