Jestem naprawdę nowy w Swift i właśnie przeczytałem, że klasy są przekazywane przez referencje, a tablice / ciągi itp. Są kopiowane.
Czy przekazywanie przez referencję jest takie samo jak w Objective-C lub Javie, w których faktycznie przekazuje się referencję „a”, czy też jest to właściwe przekazywanie przez referencję?
swift
pass-by-reference
pass-by-value
pass-by-pointer
gran_profaci
źródło
źródło
Odpowiedzi:
Rodzaje rzeczy w języku Swift
Zasada jest taka:
Instancje klasy są typy referencyjne (czyli Twój odwołanie do instancji klasy jest w rzeczywistości wskaźnik )
Funkcje są typami odwołań
Wszystko inne jest typem wartości ; „Wszystko inne” oznacza po prostu wystąpienia struktur i wystąpienia wyliczeń, ponieważ to wszystko, co znajduje się w języku Swift. Na przykład tablice i ciągi znaków są instancjami struktur. Państwo może przekazać odwołanie do jednej z tych rzeczy (jako argument funkcji) za pomocą
inout
i przy adresu, jak newacct podkreślił. Ale sam typ jest typem wartości.Co oznaczają dla Ciebie typy referencyjne
Obiekt typu referencyjnego jest w praktyce wyjątkowy, ponieważ:
Zwykłe przypisanie lub przekazanie do funkcji może dać wiele odwołań do tego samego obiektu
Sam obiekt jest zmienny, nawet jeśli odniesienie do niego jest stałą (
let
jawną lub domniemaną).Mutacja obiektu wpływa na ten obiekt, jak widać po wszystkich odniesieniach do niego.
To może być niebezpieczne, więc miej oko. Z drugiej strony przekazywanie typu referencyjnego jest wyraźnie wydajne, ponieważ tylko wskaźnik jest kopiowany i przekazywany, co jest trywialne.
Jakie typy wartości oznaczają dla Ciebie
Oczywiście przekazywanie typu wartości jest „bezpieczniejsze” i
let
oznacza to, co jest napisane: nie można zmutować instancji struktury ani instancji wyliczenia za pomocąlet
odwołania. Z drugiej strony, bezpieczeństwo uzyskuje się wykonując osobną kopię wartości, prawda? Czy to nie sprawia, że przekazywanie typu wartości jest potencjalnie kosztowne?Cóż, tak i nie. Nie jest tak źle, jak mogłoby się wydawać. Jak powiedział Nate Cook, przekazanie typu wartości niekoniecznie oznacza kopiowanie, ponieważ
let
(jawne lub dorozumiane) gwarantuje niezmienność, więc nie ma potrzeby kopiowania czegokolwiek. I nawet przejście dovar
referencji nie oznacza, że rzeczy zostaną skopiowane, tylko, że mogą być w razie potrzeby (ponieważ istnieje mutacja). Dokumentacja wyraźnie radzi, aby nie skręcać majtek.źródło
inout
niezależny od typu. To, czy coś jest przekazane przez odwołanie, jest ortogonalne do typów.Zawsze jest wartością przekazaną, gdy parametr nie jest
inout
.Jest to zawsze przekazane przez odwołanie, jeśli parametr ma wartość
inout
. Jest to jednak nieco skomplikowane ze względu na fakt, że musisz jawnie użyć&
operatora na argumencie podczas przekazywaniainout
parametru, więc może nie pasować do tradycyjnej definicji przekazywania przez referencję, w której przekazuje się zmienną bezpośrednio.źródło
inout
)inout
w rzeczywistości nie jest przekazywana przez odniesienie, ale kopiowanie na zewnątrz Gwarantuje tylko, że po wywołaniu funkcji zmodyfikowana wartość zostanie przypisana do oryginalnego argumentu. ParametryWszystko w Swift jest domyślnie przekazywane przez „kopiowanie”, więc kiedy przekazujesz typ wartości, otrzymujesz kopię wartości, a kiedy przekazujesz typ referencyjny, otrzymujesz kopię referencji ze wszystkim, co to oznacza. (Oznacza to, że kopia odniesienia nadal wskazuje na ten sam przypadek, co oryginalne odniesienie).
Używam przerażających cudzysłowów wokół „kopii” powyżej, ponieważ Swift przeprowadza wiele optymalizacji; jeśli to możliwe, nie kopiuje się, dopóki nie nastąpi mutacja lub możliwość mutacji. Ponieważ parametry są domyślnie niezmienne, oznacza to, że w większości przypadków kopiowanie się nie dzieje.
źródło
Oto mały przykład kodu do przekazywania przez odniesienie. Unikaj tego, chyba że masz do tego silny powód.
Nazwij to tak
źródło
inout
jest operatorem kopiowania na, kopiowania. Najpierw skopiuje obiekt, a następnie nadpisze oryginalny obiekt po powrocie funkcji. Chociaż może wydawać się to samo, istnieją subtelne różnice.Na blogu Apple Swift Developer znajduje się post zatytułowany Typy wartości i odniesienia, który zawiera jasną i szczegółową dyskusję na ten temat.
Cytować:
W poście na blogu Swift nadal wyjaśniono różnice z przykładami i sugerowano, kiedy należy użyć jednego nad drugim.
źródło
Klasy są przekazywane przez referencje, a inne są przekazywane domyślnie przez wartość. Możesz przekazać odwołanie za pomocą
inout
słowa kluczowego.źródło
inout
jest operatorem kopiowania na, kopiowania. Najpierw skopiuje obiekt, a następnie nadpisze oryginalny obiekt po powrocie funkcji. Chociaż może wydawać się to samo, istnieją subtelne różnice.Gdy używasz inout z operatorem infix, takim jak + =, wówczas symbol adresu & może zostać zignorowany. Domyślam się, że kompilator zakłada przekazanie przez odniesienie?
origDictionary + = newDictionaryToAdd
I ładnie, ten słownik „add” pozwala tylko pisać do oryginalnego odniesienia, więc świetnie nadaje się do blokowania!
źródło
Klasy i struktury
Jedną z najważniejszych różnic między strukturami i klasami jest to, że struktury są zawsze kopiowane, gdy są przekazywane w kodzie, ale klasy są przekazywane przez odwołanie.
Domknięcia
Jeśli przypiszesz zamknięcie do właściwości instancji klasy, a zamknięcie przechwytuje to wystąpienie, odwołując się do instancji lub jej elementów członkowskich, utworzysz silny cykl odwołań między zamknięciem a instancją. Swift używa list przechwytywania, aby przerwać te silne cykle referencyjne
ARC (automatyczne liczenie referencji)
Zliczanie odwołań dotyczy tylko wystąpień klas. Struktury i wyliczenia są typami wartości, a nie typami odwołań i nie są przechowywane ani przekazywane przez odwołanie.
źródło