Historie der Frage:
Opaque types (some) wurden mit Swift 5.1 eingeführt und eröffnen eine neue Möglichkeit zur Abstraktion des Rückgabetyps einer Funktion oder Eigenschaft, wenn der Typ dem Compiler bekannt, aber dem Benutzer verborgen ist. Dies ist eine Alternative zu protocol existentials (any Protocol), aber mit fester Bindung an einen bestimmten Typ innerhalb der Funktion.
Problem: Wenn eine Funktion ein Protokoll mit associatedtype zurückgibt (z.B. Sequence), kann man nicht direkt schreiben:
func makeNumberSequence() -> Sequence { ... } // Fehler
Protokoll-Existentials erlauben es, jede Implementierung zurückzugeben, garantieren jedoch nicht, dass bei jedem Aufruf derselbe Typ zurückgegeben wird:
func foo() -> any View { ... }
Dies führt zu Unvorhersehbarkeiten und schwachem type safety.
Lösung: Verwendung eines opaque result type:
func makeNumbers() -> some Sequence { [1, 2, 3] }
Jetzt weiß der Compiler genau, welcher Rückgabewert tatsächlich ist, aber er ist von außen verborgen. Dies ermöglicht Leistungsoptimierungen, Sicherheit, die Verwendung von SwiftUI DSL und erleichtert den Typaustausch zwischen Modulen.
Wesentliche Eigenschaften:
Können opaque types zur Speicherung von Werten (wie Klassenproperties) verwendet werden?
Nein. Opaque types gelten nur für Rückgabewerte von Funktionen oder berechneten Eigenschaften. Zur Speicherung von Werten oder Wertarrays verwendet man Existentials (any Protocol).
Können verschiedene Zweige einer Funktion unterschiedliche Typen mit some zurückgeben?
Nein. Der Compiler verlangt, dass beide (oder alle) Zweige denselben konkreten Typ zurückgeben, andernfalls gibt es einen Fehler:
func foo(flag: Bool) -> some Sequence { if flag { return [1, 2, 3] } else { return ["a", "b", "c"] // Fehler } }
Kann man some verwenden, um den Rückgabewerttyp zwischen mehreren Funktionen zu identifizieren?
Nein. Jede Funktion mit some gibt ihren eigenen einzigartigen versteckten Typ zurück, selbst wenn es sich tatsächlich um dasselbe Array handelt. Das Ergebnis einer Funktion kann nicht als Parameter in einer anderen Funktion verwendet werden, wenn beide some mit unterschiedlichen Protokollen oder unterschiedlichen versteckten Typen verwenden.
Im Projekt wird alles über any Protocol zurückgegeben, Sammlungen verlieren ihren Typ, es treten Bugs beim Downcasting auf, die Kompilierungsoptimierung wird verlangsamt.
Vorteile:
Nachteile:
In SwiftUI-Design geben Komponenten some View zurück, jedes Modul definiert den inneren Typ klar. Die Bundle-Größe wird reduziert, der Build wird schneller.
Vorteile:
Nachteile: