Storia della domanda:
Il Subscript è un meccanismo per accedere ai valori all'interno di collezioni, strutture e altri tipi usando le parentesi quadre. È stato aggiunto in Swift per analogia con altri linguaggi (ad esempio, l'indicizzazione negli array di Python, l'operatore [] in C++/Java), per rendere il lavoro con collezioni e oggetti simili più intuitivo.
Problema:
Non tutti i tipi supportano per impostazione predefinita l'accesso per indice come un array. Quando abbiamo una struttura o una classe con dati, l'accesso agli elementi è spesso logico realizzarlo tramite una sintassi familiare (tipo myObject[index]), piuttosto che con un metodo.
Soluzione:
Swift consente di implementare autonomamente il subscript per qualsiasi tipo personalizzato. Può essere creato sia per lettura che per scrittura. Esempio: una struttura che implementa un subscript per lavorare con una matrice quadrata:
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), "Indice fuori intervallo") return grid[(row * size) + column] } set { precondition(indexIsValid(row, column), "Indice fuori intervallo") 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
Caratteristiche chiave:
I subscript possono essere utilizzati solo per collezioni?
No, i subscript possono essere implementati per qualsiasi tipo: struttura, classe, enum. Il tipo di dati all'interno non deve essere necessariamente una collezione, l'importante è la logica di gestione delle richieste tramite il subscript.
Posso avere più subscript con firme diverse in un unico tipo?
Sì, è permesso sovraccaricare il subscript con firme di parametri diverse:
struct Example { subscript(index: Int) -> Int { return index } subscript(key: String) -> String { return key.uppercased() } }
È consentito utilizzare il subscript come proprietà calcolata senza set?
Sì, il subscript può essere solo in lettura (solo get), quindi un tentativo di scrittura genererà un errore di compilazione.
struct ReadOnly { subscript(index: Int) -> Int { index * index } }
In una grande struttura è stato implementato un subscript senza verifica del range, portando a un crash dell'applicazione con un indice non valido.
Pro:
Contro:
La matrice è stata implementata con precondition sul range degli indici. Qualsiasi errore viene catturato immediatamente, non finisce in produzione.
Pro:
Contro: