Hintergrund des Themas:
Subscript ist ein Mechanismus, um auf Werte innerhalb von Sammlungen, Strukturen und anderen Typen mithilfe von eckigen Klammern zuzugreifen. Es wurde in Swift ähnlich wie in anderen Sprachen (z. B. Indizierung in Python-Arrays, der Operator [] in C++/Java) hinzugefügt, um die Arbeit mit Sammlungen und ähnlichen Objekten intuitiver zu gestalten.
Problem:
Nicht alle Typen unterstützen standardmäßig den Zugriff über Indizes wie Arrays. Wenn wir eine Struktur oder Klasse mit Daten haben, ist der Zugriff auf die Elemente oft logischer über die gewohnte Syntax (zum Beispiel myObject[index]) statt über eine Methode.
Lösung:
Swift ermöglicht es, Subscripts selbst für jeden benutzerdefinierten Typ zu implementieren. Man kann es sowohl zum Lesen als auch zum Schreiben gestalten. Ein Beispiel ist eine Struktur, die ein Subscript für die Arbeit mit einer quadratischen Matrix implementiert:
struct Matrix { let size: Int private var grid: [Int] init(size: Int) { self.size = size self.grid = Array(repeating: 0, count: size * size) } subscript(row: Int, column: Int) -> Int { get { precondition(indexIsValid(row, column), "Index außerhalb des Bereichs") return grid[(row * size) + column] } set { precondition(indexIsValid(row, column), "Index außerhalb des Bereichs") grid[(row * size) + column] = newValue } } private func indexIsValid(_ row: Int, _ column: Int) -> Bool { return row >= 0 && row < size && column >= 0 && column < size } } var m = Matrix(size: 3) m[1,2] = 7 print(m[1,2]) // 7
Wichtige Merkmale:
Können Subscripts nur für Sammlungen verwendet werden?
Nein, Subscripts können für beliebige Typen implementiert werden: Struktur, Klasse, Enum. Der Datentyp muss nicht unbedingt eine Sammlung sein, wichtig ist die Logik zur Verarbeitung von Anfragen über Subscripts.
Kann man mehrere Subscripts mit unterschiedlicher Signatur in einem Typ haben?
Ja, es ist erlaubt, Subscripts mit unterschiedlichen Parameter-Signaturen zu überladen:
struct Example { subscript(index: Int) -> Int { return index } subscript(key: String) -> String { return key.uppercased() } }
Ist es erlaubt, Subscript als berechnete Eigenschaft ohne set zu verwenden?
Ja, Subscript kann nur lesbar sein (get-only), dann führt ein Schreibversuch zu einem Kompilierungsfehler.
struct ReadOnly { subscript(index: Int) -> Int { index * index } }
In einer großen Struktur wird ein Subscript ohne Bereichsprüfung implementiert, was zum Absturz der Anwendung bei einem ungültigen Index führt.
Vorteile:
Nachteile:
Die Matrix wurde mit einer Vorbedingung für den Indexbereich implementiert. Jeder Fehler wird sofort abgefangen, gelangt nicht in die Produktion.
Vorteile:
Nachteile: