Poruszanie się po głowie Niezmienność

13

Jestem nowy w programowaniu obiektowym, a jedną z koncepcji, którą zajęło mi trochę czasu, jest niezmienność. Myślę, że żarówka zgasła ostatniej nocy, ale chcę zweryfikować:

Kiedy napotykam stwierdzenia, że ​​niezmiennego obiektu nie można zmienić, jestem zdziwiony, ponieważ mogę na przykład wykonać następujące czynności:

NSString *myName = @"Bob";
myName = @"Mike";

Tam właśnie właśnie zmieniłem nazwę, niezmiennego typu NSString. Mój problem polega na tym, że słowo „obiekt” może odnosić się do fizycznego obiektu w pamięci lub abstrakcja „mojaNazwa”. Poprzednia definicja dotyczy pojęcia niezmienności.

Jeśli chodzi o zmienną, bardziej przejrzystą (dla mnie) definicją niezmienności jest to, że wartość niezmiennego obiektu można zmienić tylko poprzez zmianę jego położenia w pamięci, tj. Jego odniesienia (znanego również jako jego wskaźnik).

Czy to prawda, czy wciąż jestem zagubiony w lesie?

Michael Mangold
źródło
13
Twój typ nie jest NSString, to „ wskaźnik do i NSString”, który nie jest niezmienny. I nic obiektywnego C wiem, ale zgaduję, że w swojej przykład @"Mike"tworzy nową instancję NSStringi przypisanie go do wskaźnika , myName. Więc nie zmieniłeś obiektu, który myNamewskazywał, tylko to, na co wskazywał.
fwgx
2
@fwgx Umieść to jako odpowiedź, a dostaniesz moje poparcie.
Gulshan
Dziękuję wszystkim za wszystkie odpowiedzi, są bardzo pomocne. Rozumiem teraz, że niezmienny obiekt jest wartością w pamięci, a nie zmienną, która na nią wskazuje.
Michael Mangold
@Gulshan Gotowe, patrz poniżej ....
fwgx
Aby zrozumieć niezmienność, zalecam naukę języka programowania, który wyraźnie rozdziela powiązanie (tj. Nadawanie nazw obiektom) ze zmiennością (tj. Pozwalanie na przypisanie nazwy do innego obiektu). ML (pod dowolnymi postaciami: SML, Ocaml, F #) jest dobrym przykładem.
Gilles „SO- przestań być zły”,

Odpowiedzi:

4

Wygląda na to, że zmierzasz we właściwym kierunku, ale jeszcze go nie rozumiesz. To jest źle:

Tam właśnie właśnie zmieniłem nazwę, niezmiennego typu NSString. Mój problem polega na tym, że słowo „obiekt” może odnosić się do fizycznego obiektu w pamięci lub abstrakcja „mojaNazwa”.

We fragmencie kodu myNamenie jest on niezmienny NSString, jest typu zmiennegoNSString* (wskaźnik do NSString). Wygląda na to, że kluczową rzeczą, której brakuje, jest zrozumienie, że wskaźnik jest po prostu inną wartością i ma całkowicie odrębne życie od rzeczy, na którą wskazuje (lub rzeczy, jeśli zmienisz go w trakcie jego życia).

Mówisz:

... wartość niezmiennego obiektu można zmienić tylko poprzez zmianę jego położenia w pamięci, tj. jego odwołania (znanego również jako wskaźnik).

To jest źle. Obiekt nie jest właścicielem wskaźników, które na niego wskazują, ani też lokalizacja pamięci obiektu nie jest kontrolowana ani w żaden inny sposób nie ma na nią wpływu.

Zatem dwa NSStringobiekty w twoim przykładzie ( @"Bob"i @"Mike") są całkowicie oddzielone od myNamezmiennej. Są również całkowicie oddzielone od siebie. Kiedy zmienisz myNamena wskaż na @"Mike"zamiast wskazywać na @"Bob", nie zmieniasz NSStringobiektów.


Dla kompletności zwrócę uwagę na to, że zbieracze śmieci powodują, że jest to bardziej złożone, ponieważ zmiany wskaźników mogą wpływać na obiekty, na które wskazują (ed). Jest to jednak szczegół implementacji, który nie powinien wpływać na obserwowalne zachowanie kodu.

John Bartłomiej
źródło
17

Jesteś zagubiony w słowach. Niezmienność oznacza: Dopóki nie zmienisz zmiennej, zawsze będzie ona „zawierać” tę samą wartość, bez względu na to, co zrobisz z innymi zmiennymi.

Kontrprzykład w C (nieco uproszczony, przy założeniu architektury, która to umożliwia):

 char *a = "Hello World";
 char *b = a;
 b[0] = 'Y';

Teraz już nie „zawiera” (tzn. Wskazuje na) ciąg „Hello World”, ale zamiast tego jest „Yello World”.

W językach, w których ciągi są niezmienne, takich jak Java i (EDIT: safe) C #, nie można tego zrobić. Nie ma mowy. Oznacza to, że każda część programu może bezpiecznie przechowywać odniesienie do łańcucha i polegać na tym, że jego zawartość nigdy się nie zmienia; w przeciwnym razie musieliby stworzyć kopię, aby być po bezpiecznej stronie.

Ale zmienna wciąż jest zmienna. Możesz pozwolić mu wskazywać inny obiekt. Tyle, że sam obiekt nie zmieni się za twoimi plecami.

użytkownik 281377
źródło
1
Technicznie możesz modyfikować zawartość łańcucha w C #, wystarczy użyć unsafekodu.
Aaronaught
1
Aaronaught: Dzięki za informację, masz rację; dla wszystkich, którzy muszą wiedzieć, jak: msdn.microsoft.com/en-us/library/ms228599.aspx
user281377
10

Mylisz zmienne z obiektami. Zmienne mogą być używane do przechowywania odniesień do obiektów, ale NIE są to obiekty. Są to obiekty, które są niezmienne, a nie zmienne, więc możesz zmienić zmienną z jednego obiektu na drugi, ale nie możesz zmienić atrybutów obiektu, jeśli jest niezmienny.

Pomyśl o tym obiekcie jak o głośnym, pijanym sąsiadu. Jeśli jest rozsądny (zmienny), być może będziesz w stanie zapukać do jego drzwi i przekonać go do stylu życia, w którym nie robi tyle hałasu. Ale jeśli jest niezmienny, jedyną zmianą jest nadzieja, że ​​ktoś się wprowadzi!

Kilian Foth
źródło
3
Miałem kilku sąsiadów, których chciałbym wyciszyć.
Dave Nay
Nie sądzę, żebyś potrzebował swojego przykładu w drugim akapicie, ponieważ twoje wyjaśnienie jest wystarczająco dobre. IMO przykład może po prostu pomylić. Jednak +1 za zwięzłą odpowiedź na pytanie faceta.
Paul McCabe
@DaveNay: Przepraszam za ukrytą grę słów. W ogóle nie był przeznaczony.
Kilian Foth
6

Zmienna nie jest obiektem. Zmienna to nazwa, która odnosi się do obiektu (lub bardziej ogólnie wartości).

Na przykład „bramkarz” to nazwa, której używamy w odniesieniu do obiektu (osoby) odpowiedzialnej za obronę celu. Ale jeśli zastąpię tę osobę inną osobą (ponieważ ta pierwsza jest ranna lub coś w tym rodzaju), nowa osoba jest teraz nazywana „bramkarzem”.

Instrukcja przypisania powoduje, że zmienne są zmienne (niektóre języki, takie jak Haskell, nie mają go i faktycznie używają niezmiennych zmiennych). Pozwala przedefiniować znaczenie nazwy, a tym samym ponownie przypisać wartość.

Teraz same obiekty mogą być niezmienne. Kilka tysięcy lat temu można było pomyśleć o diamentach jako niezmiennych. Bez względu na to, co zrobiłeś z diamentem, nie możesz go zmodyfikować. Bez względu na to, czy nazwałeś go waggawooga (luźno oznacza to „największy błyszczący kamień naszego plemienia”), czy przestałeś go tak nazywać (ponieważ znalazłeś większy), diament pozostał ten sam. W przeciwieństwie do tego kawałek drewna, który rzeźbiłeś na zabawnych zdjęciach swoją waggawoogą, nie pozostał taki sam. Okazało się zmienne. Nawet jeśli miał przez cały czas tę samą nazwę.

Zarówno zmienne, jak i wartości mogą być niezmienne (niezależnie). W tym przypadku są to obiekty niezmienne. Po zbudowaniu NSStringnie można go modyfikować. Możesz nazywać go imionami i przekazywać, ale pozostanie taki sam. W przeciwieństwie do tego NSMutableStringmożna go zmienić po utworzeniu, na przykład przez wywołanie setStringmetody.

back2dos
źródło
Uwielbiam porównanie waggawooga!
Michael K
Żeby nie pomylić oryginalnego plakatu bardziej niż to konieczne: chociaż twoje twierdzenie, że zmienna nie jest przedmiotem, jest dobre, zmienna tak naprawdę nie jest zdefiniowana jako „nazwa, która odnosi się do wartości”. Zmienna jest prawdopodobnie nazwana i odnosi się do miejsca przechowywania, które zawiera wartość. W wielu językach programowania zmienne nie muszą być nazywane, aw wielu językach ta sama zmienna może mieć więcej niż jedną nazwę.
Eric Lippert,
4

Myślę, że czujesz się zagubiony, ponieważ łączysz dwie koncepcje: sam obiekt i nazwę zmiennej związaną z tym obiektem.

Niezmiennych obiektów nie można zmienić. Kropka. Jednak nazwa zmiennej (symbol) związana z niezmiennym obiektem, może zostać zmodyfikowana, aby była powiązana z innym niezmiennym obiektem.

Innymi słowy, to, co zrobiłeś w tych dwóch liniach, to:

  1. utwórz niezmienny ciąg znaków o wartości „Bob”
  2. powiązać symbol myNamez tym obiektem
  3. utwórz niezmienny ciąg znaków o wartości „Mike”
  4. powiązać symbol myNamez tym obiektem
vartec
źródło
2

Twój preferowany typ nie jest to NSString, że jest to „ wskaźnik doNSString ”, który nie jest niezmienna. Nic nie wiem o celu C, ale zgaduję w twoim przykładzie, który @"Mike"tworzy nową instancję NSStringi przypisuje ją do wskaźnika myName . Więc nie zmieniły się obiekt, który myNamezostał skierowany w celu, tylko co to wskazywał.

fwgx
źródło
0

Oto przykład zmiennego obiektu: tablica charw C:

char str[10];

Mogę zmienić zawartość z strdo treści mojego serca (tak długo, jak to jest nie więcej niż 10 znaków). Aby mógł zostać rozpoznany jako ciąg przez funkcje biblioteki ciągów C, musi mieć końcowe 0, aby mógł przechowywać ciągi o długości do 9 znaków:

strcpy(str, "hello"); // str now contains the string "hello\0"
strcpy(str, "world"); // str now contains the string "world\0"

str[0] = 'W';         // str now contains "World\0"

i tak weiter .

Porównaj to z obiektem łańcuchowym w Javie:

String foo = "Hello";

Instancja ciągu (fragment pamięci zawierający znaki „H”, „e”, „l”, „l” i „o”) nie może być modyfikowany; Nie mogę zmienić żadnej zawartości tego ciągu. Kiedy piszesz coś takiego

foo = foo + " World";

nie dołączasz „World” na końcu wystąpienia „Hello”; tworzysz nową instancję , kopiujesz do niej „Hello World” i aktualizujesz, fooaby odwoływała się do tej nowej instancji ciągu.

foosam nie zawiera instancji ciągu; odnosi się tylko do tego wystąpienia (podobnie do wskaźnika w C lub Obj-C), dlatego typy takie jak String są nazywane typami referencyjnymi.

John Bode
źródło