Historia pytania:
Typy nieprzezroczyste (some) pojawiły się w Swift 5.1 i otworzyły nowy sposób abstrakcji zwracanego wyniku funkcji lub właściwości, gdy typ jest znany kompilatorowi, ale ukryty przed użytkownikiem. To alternatywa dla egzystencjalnych protokołów (any Protocol), ale z sztywnym powiązaniem z konkretnym typem wewnątrz funkcji.
Problem: Kiedy funkcja zwraca protokół z associatedtype (na przykład, Sequence), nie można bezpośrednio napisać:
func makeNumberSequence() -> Sequence { ... } // błąd
Egzystencjalne protokoły pozwalają zwracać dowolną implementację, ale nie gwarantują tego samego typu przy każdym wywołaniu:
func foo() -> any View { ... }
Prowadzi to do nieprzewidywalności i słabego bezpieczeństwa typów.
Rozwiązanie: Użyj typów wynikowych nieprzezroczystych:
func makeNumbers() -> some Sequence { [1, 2, 3] }
Teraz kompilator dokładnie zna faktyczny typ zwracany, ale jest on ukryty na zewnątrz. To zapewnia optymalizacje wydajności, bezpieczeństwo, pozwala na użycie SwiftUI DSL, ułatwia wymianę typów między modułami.
Kluczowe cechy:
Czy typy nieprzezroczyste mogą być używane do przechowywania wartości (jak właściwości klasy)?
Nie. Typy nieprzezroczyste stosuje się tylko do zwracanych wartości funkcji lub właściwości obliczanych. Do przechowywania wartości lub tablic wartości używa się egzystencjalnych (any Protocol).
Czy różne gałęzie jednej funkcji mogą zwracać różne typy z some?
Nie. Kompilator wymaga, aby obie (lub wszystkie) gałęzie zwracały ten sam konkretny typ, w przeciwnym razie wystąpi błąd:
func foo(flag: Bool) -> some Sequence { if flag { return [1, 2, 3] } else { return ["a", "b", "c"] // błąd } }
Czy można używać some do identyfikacji zwracanego typu między wieloma funkcjami?
Nie. Każda funkcja z some zwraca swój unikalny ukryty typ, nawet jeśli faktycznie jest to ta sama tablica. Nie można używać wyniku jednej funkcji jako parametru w drugiej, jeśli obie używają some z różnymi protokołami lub różnymi ukrytymi typami.
W projekcie wszystko jest zwracane przez any Protocol, kolekcje tracą typizację, pojawiają się błędy przy downcast-e, spowalnia to kompilację.
Plusy:
Minusy:
W projektowaniu SwiftUI komponenty zwracają some View, każdy moduł wyraźnie definiuje wewnętrzny typ. Rozmiar pakietu się zmniejsza, kompilacja przyspiesza.
Plusy:
Minusy: