Il meccanismo degli subscript in Swift è apparso insieme al linguaggio nel 2014 ed è progettato per accedere ai dati delle collezioni con una sintassi più conveniente. Gli subscripts consentono di accedere agli elementi di array, dizionari e altre collezioni tramite parentesi quadre. L'Swift moderno consente di creare subscripts personalizzati per i propri tipi, rendendo l'API intuitiva, come quelle delle strutture dati standard.
Problema: In passato, i metodi di accesso sembravano più ingombranti (ad esempio, tramite .getElement(at:)), mentre lo subscript rende l'interazione con il tipo più concisa. Tuttavia, un'implementazione errata può portare a codice non ottimale o a errori di accesso fuori dalla collezione.
Soluzione: Per implementare lo subscript si utilizza la parola chiave subscript, seguita dai parametri e dal valore restituito. Lo subscript può essere sia solo in lettura che sia in lettura e scrittura. Inoltre, gli subscripts possono essere sovraccaricati per parametri diversi.
Esempio di codice:
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, "Indice fuori intervallo") return grid[(row * columns) + column] } set { assert(row >= 0 && row < rows && column >= 0 && column < columns, "Indice fuori intervallo") grid[(row * columns) + column] = newValue } } } var matrix = Matrix(rows: 2, columns: 2) matrix[0, 1] = 3.14 print(matrix[0, 1]) // 3.14
Caratteristiche chiave:
È possibile assegnare uno subscript solo in lettura? O lo subscript deve sempre avere get e set?
Lo subscript può essere solo in lettura (solo get), se nell'implementazione manca set. Non è necessario implementare entrambi gli accessori, il che è analogo alle proprietà.
Esempio di codice:
subscript(index: Int) -> Int { get { return index * 2 } }
È possibile passare parametri mutabili tramite inout in subscript?
No, lo subscript non supporta parametri inout nella firma. Tutti i parametri degli subscripts vengono accettati come costanti let all'interno del corpo degli accessor.
Possono gli subscripts restituire un tipo opzionale?
Sì, gli subscripts possono restituire valori opzionali, il che è comodo, ad esempio, per l'accesso sicuro agli elementi della collezione senza il rischio di superare i limiti dell'array.
Esempio di codice:
extension Array { subscript(safe index: Int) -> Element? { return indices.contains(index) ? self[index] : nil } }
Implementazione dello subscript senza verifica dell'uscita dai limiti per il tipo composito matrix, che porta a un crash dell'applicazione in caso di errori con l'indice.
Pro:
Contro:
Aggiunta di una versione opzionale dello subscript per l'indicizzazione sicura e la gestione degli errori, rendendo l'API esplicita e protetta.
Pro:
Contro: