Storia della questione:
In Swift fino alla versione 5, quando si restituiva un valore conforme a un protocollo con associated type, ci si trovava spesso ad affrontare delle limitazioni: il tipo non poteva essere utilizzato come tipo di ritorno direttamente, era richiesto il type erasure. Per migliorare la leggibilità e le prestazioni, sono stati introdotti gli opaque types: valori restituiti tramite la parola chiave some, che consentono di descrivere astrazioni nelle interfacce pubbliche.
Problema:
Quando è necessario nascondere il tipo reale del valore restituito, mantenendo l'astrazione tramite un protocollo, ma evitando i costi del dynamic dispatch e del type erasure. Ad esempio, restituendo collezioni, sequenze, componenti view.
Soluzione:
Gli opaque types consentono di restituire un tipo conforme al protocollo, nascondendo la sua implementazione specifica. Il compilatore conosce il tipo reale, ma la parte chiamante no.
Esempio:
protocol Shape { func area() -> Double } struct Circle: Shape { var radius: Double func area() -> Double { Double.pi * radius * radius } } func makeCircle() -> some Shape { return Circle(radius: 3) } let s = makeCircle() print(s.area()) // funziona
Caratteristiche chiave:
someQual è la differenza tra l'opaque type (some Protocol) e il tipo restituito da un Protocol?
L'opaque type ha un'implementazione concreta durante la compilazione (anche se è nascosta dall'esterno). Quando si restituisce Protocol, viene eseguito il dynamic dispatch, non c'è type safety se ci sono associated type.
Posso restituire tipi diversi utilizzando some Protocol in una sola funzione?
No. Tutti i return devono restituire lo stesso tipo reale:
func maker(flag: Bool) -> some Shape { if flag { return Circle(radius: 3) } else { return Square(size: 2) // Errore: il tipo di ritorno non coincide } }
Può l'associatedtype all'interno di un Protocol essere utilizzato tramite some Protocol?
Sì. È proprio per questo (in primo luogo) che è necessario l'opaque type:
protocol View { associatedtype Body } func makeView() -> some View { /* ... */ }
La funzione restituisce un protocol senza opaque, non consente di utilizzare metodi con associatedtype, è necessario un complesso type erasure, il codice non si compila o funziona in modo subottimale.
Vantaggi:
Svantaggi:
ViewBuilder in SwiftUI utilizza some View, nascondendo i dettagli, migliorando la sicurezza dei tipi, accelerando la compilazione e il runtime.
Vantaggi:
Svantaggi: