ProgrammazioneSviluppatore iOS

Che cos'è il subscripting in Swift e come implementare un subscript personalizzato per una propria struttura?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

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:

  • Il subscript può accettare qualsiasi numero di argomenti, non solo un indice
  • Viene implementato utilizzando la parola chiave subscript e può essere solo per lettura o per lettura/scrittura
  • Consente di creare un'API comoda e leggibile per collezioni o strutture personalizzate

Domande trabocchetto.

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 } }

Errori comuni e anti-pattern

  • Mancanza di verifica del range degli indici (Indice fuori intervallo)
  • Violazione del principio “responsabilità singola” — il subscript contiene logica di business e non solo accesso ai dati
  • Firme di subscript troppo complesse e non intuitive

Esempio dalla vita reale

Caso negativo

In una grande struttura è stato implementato un subscript senza verifica del range, portando a un crash dell'applicazione con un indice non valido.

Pro:

  • Prototipo veloce
  • Meno codice

Contro:

  • Alta probabilità di crash a runtime
  • Difficoltà nel debug a causa di un errore non ovvio

Caso positivo

La matrice è stata implementata con precondition sul range degli indici. Qualsiasi errore viene catturato immediatamente, non finisce in produzione.

Pro:

  • Sicurezza nel lavoro con gli input
  • Facile diagnosi e supporto

Contro:

  • Un po' più di codice e controlli, ma affidabilità superiore