ProgrammazioneMiddle/Senior iOS Developer

Cosa sono i subscripts in Swift e come possono essere sovrascritti o estesi? Fornisci un esempio di utilizzo avanzato.

Supera i colloqui con l'assistente IA Hintsage

Risposta.

I subscripts in Swift offrono una sintassi conveniente per accedere agli elementi di una collezione, contenitore o tipo personalizzato tramite indici, proprio come negli array e nei dizionari. Possono essere dichiarati e sovrascritti nelle proprie classi, strutture e enumerazioni.

Storia della domanda

I subscripts sono stati introdotti in Swift come un modo per unificare l'accesso indicizzato agli oggetti, iniziando dalle collezioni e poi espandendosi a qualsiasi tipo personalizzato. L'obiettivo principale è aumentare l'espressività e la leggibilità, trasformare i metodi di accesso ai dati in una sintassi "naturale" che ricorda il lavoro con un array.

Problema

In altri linguaggi (ad esempio, Java), l'accesso a un elemento di una struttura avviene tramite metodi get/set, il che rende il codice ingombrante. Il desiderio di una migliore leggibilità e di facilitare l'accesso ai dati ha portato all'istituzione dei subscripts. In Swift è necessaria particolare attenzione all'accesso sicuro, ai getter e ai setter, agli errori potenziali e ai valori di ritorno optional.

Soluzione

I subscripts possono essere dichiarati in qualsiasi classe, struttura o enumerazione utilizzando la parola chiave subscript. Si supportano anche più overload in base ai parametri e ai tipi di ritorno.

Esempio di subscript personalizzato:

struct Matrix { let rows: Int, columns: Int private var grid: [Double] init(rows: Int, columns: Int) { self.rows = rows self.columns = columns grid = Array(repeating: 0.0, count: rows * columns) } subscript(row: Int, column: Int) -> Double { get { precondition(row >= 0 && row < rows) precondition(column >= 0 && column < columns) return grid[(row * columns) + column] } set { precondition(row >= 0 && row < rows) precondition(column >= 0 && column < columns) grid[(row * columns) + column] = newValue } } } var matrix = Matrix(rows: 2, columns: 2) matrix[1, 1] = 3.14 print(matrix[1, 1]) // 3.14

Caratteristiche chiave:

  • Possono essere definiti più subscripts con tipi e numero di parametri diversi
  • Un subscript può essere solo get, oppure get/set
  • È possibile utilizzare subscripts con diversi tipi di indici, anche con intervalli e stringhe

Domande trabocchetto.

È possibile dichiarare un subscript solo con il getter, senza setter?

Sì. Se il subscript è necessario solo per la lettura, è sufficiente implementare solo il get.

struct ReadOnlyArray { private let items = [1, 2, 3] subscript(index: Int) -> Int { get { return items[index] } } }

È consentito dichiarare più subscripts con diverse firme nello stesso tipo?

Sì, i subscripts possono essere sovraccaricati (overloaded) in base al numero e al tipo di parametri.

struct Collection { subscript(index: Int) -> String { ... } subscript(key: String) -> Int? { ... } }

Può un subscript essere dichiarato in un protocollo e implementato in una struttura/classe?

Sì, i protocolli possono richiedere l'implementazione di subscripts, e i tipi specifici sono obbligati a implementarli.

protocol MySubscriptable { subscript(index: Int) -> String { get set } } struct SubData: MySubscriptable { private var items = ["a", "b"] subscript(index: Int) -> String { get { return items[index] } set { items[index] = newValue } } }

Errori tipici e anti-pattern

  • Esecuzione di accessi non sicuri senza controlli sui limiti (precondition, bounds check)
  • Errori di tipo dati per i parametri del subscript
  • Uso eccessivo di subscripts senza necessità, dove sarebbe meglio usare metodi

Esempio dal vivo

Caso negativo

Un sviluppatore ha implementato un subscript senza controlli sui limiti. Di conseguenza, l'applicazione crashava con un errore durante l'esecuzione quando si tentava di accedere a un indice inesistente.

Pro: Il codice è diventato più conciso.

Contro: L'applicazione ha cominciato a chiudersi inaspettatamente a causa di errori improvvisi.

Caso positivo

Implementazione di un subscript con precondition e possibilità di ritorno di optional o lancio di errori.

Pro: Il codice è diventato più sicuro per l'utente, gli errori possono essere gestiti.

Contro: È necessaria un'ulteriore logica per la gestione degli errori e considerare il comportamento per indici non validi.