Я новичок в объектно-ориентированном программировании, и одна концепция, на которую у меня ушло некоторое время, - это неизменность. Я думаю, что лампочка погасла прошлой ночью, но я хочу проверить:
Когда я сталкиваюсь с утверждениями, что неизменяемый объект не может быть изменен, я озадачен, потому что я могу, например, сделать следующее:
NSString *myName = @"Bob";
myName = @"Mike";
Там я только что изменил myName неизменяемого типа NSString. Моя проблема в том, что слово «объект» может относиться к физическому объекту в памяти или абстракции «myName». Первое определение относится к понятию неизменности.
Что касается переменной, то более ясное (для меня) определение неизменяемости состоит в том, что значение неизменяемого объекта можно изменить только путем изменения его местоположения в памяти, то есть его ссылки (также называемой указателем).
Это правильно, или я все еще заблудился в лесу?
источник
NSString
является " указателем на" иNSString
не является неизменным. Я ничего не знаю об объективном C, но я предполагаю , что в вашем примере , что@"Mike"
создает новый экземплярNSString
и присваивает его указатель ,myName
. Таким образом, вы не изменили объект, на которыйmyName
указывал, только то, на что он указывал.Ответы:
Похоже, вы движетесь в правильном направлении, но пока не совсем поняли. Это не правильно:
В фрагменте кода,
myName
не неизменного типаNSString
, он имеет изменяемый типNSString*
(указатель на NSString). Похоже, что ключевая вещь, которую вы упускаете, - это понять, что указатель - это просто другое значение , и он имеет полностью отдельную жизнь от того, на что он указывает (или вещей, если вы меняете его частично в течение всей своей жизни).Ты говоришь:
Это не правильно. Объект не владеет указателями, которые указывают на него, а также на расположение объекта в памяти не контролируется или иным образом не зависит от указателей на него.
Итак, два
NSString
объекта в вашем примере (@"Bob"
и@"Mike"
) полностью отделены отmyName
переменной. Они также полностью отделены друг от друга. Когда вы изменяете,myName
чтобы указать@"Mike"
вместо того, чтобы указывать@"Bob"
, вы не меняетеNSString
объекты.Для полноты заметки отметим, что сборщики мусора усложняют ситуацию, так как изменения в указателях могут повлиять на объекты, на которые они указывают (ed). Однако это деталь реализации, которая не должна влиять на наблюдаемое поведение кода.
источник
Вы потерялись в словах. Неизменность означает: пока вы не измените переменную, она всегда будет «содержать» одно и то же значение, независимо от того, что вы делаете с другими переменными.
Контрпример в C (немного упрощенный, предполагая архитектуру, которая позволяет это):
Теперь больше не «содержит» (то есть указывает на) строку «Hello World», но вместо этого это «Yello World».
В языках, где строки являются неизменяемыми, таких как Java и (EDIT: safe) C #, вы не можете сделать это. Ни за что. Это означает, что каждая часть программы может безопасно хранить ссылку на строку и полагать, что ее содержимое никогда не изменится; в противном случае им пришлось бы создать копию, чтобы быть в безопасности.
Но переменная все еще изменчива. Вы можете позволить ему указывать на другой объект. Просто сам объект не изменится за вашей спиной.
источник
unsafe
код.Вы путаете переменные с объектами. Переменные могут использоваться для хранения ссылок на объекты, но они НЕ являются объектами. Это неизменяемые объекты, а не переменные, поэтому вы можете изменять переменную от одного объекта к другому, но вы не можете изменить атрибуты объекта, если он неизменен.
Думайте об объекте как о громком пьяном соседе. Если он разумный (изменчивый), вы можете постучать в его дверь и превратить его в образ жизни, в котором он не делает столько шума. Но если он неизменен, твое единственное изменение - надеяться, что кто-то еще придет!
источник
Переменная не является объектом. Переменная - это имя, которое относится к объекту (или, в более общем случае, к значению).
Например, «вратарь» - это имя, которое мы используем для обозначения объекта (человека), ответственного за защиту цели. Но если я заменю этого человека другим (потому что первый получил травму или еще что-то), новый человек теперь называется «вратарь».
Оператор присваивания - это то, что делает переменные изменяемыми (некоторые языки, такие как Haskell, не имеют его и фактически используют неизменяемые переменные). Это позволяет вам переопределить значение имени и тем самым переназначить значение.
Теперь сами объекты могут быть неизменными. Несколько тысяч лет назад можно было подумать, что бриллианты неизменны. Неважно, что вы сделали с бриллиантом, вы не можете изменить его. Назовите ли вы его waggawooga (в широком смысле означает «самый большой блестящий камень нашего племени») или перестали называть его так (потому что вы нашли больший), бриллиант остался прежним. В отличие от этого, кусок дерева, который вы вырезали на забавных картинках с помощью вашего waggawooga, не остался прежним. Это оказалось изменчивым. Даже если у него было одно и то же имя все время.
И переменные, и значения могут быть неизменными (независимо). В данном случае это неизменные объекты. После того как вы построите
NSString
, вы не можете изменить его. Вы можете называть это именами и передавать их, но это останется прежним. В отличие от этого,NSMutableString
может быть изменено после создания, например, путем вызоваsetString
метода.источник
Я думаю, что вы чувствуете себя потерянным, потому что вы смешиваете два понятия: сам объект и имя переменной, связанной с этим объектом.
Неизменяемые объекты не могут быть изменены. Период. Однако имя переменной (символ), привязанное к неизменяемому объекту, может быть изменено для привязки к другому неизменяемому объекту.
Другими словами, то, что вы сделали в этих двух строках:
myName
к этому объектуmyName
к этому объектуисточник
Ваш ваш тип не является
NSString
, это « указатель наNSString
», который не является неизменным. Я ничего не знаю о цели C, но я предполагаю, что в вашем примере@"Mike"
создается новый экземпляр объектаNSString
и назначается его указателюmyName
. Таким образом , вы не изменили объект , которыйmyName
был указывая на, как раз то , что она показывала.источник
Вот пример изменяемого объекта: массив
char
в C:Я могу изменить содержимое из
str
к содержанию моего сердца (так долго , как это не более 10 символов). Для того, чтобы он был распознан как строка библиотечными функциями C, должен быть завершающий 0, чтобы он мог содержать строки длиной до 9 символов:и так легче .
Сравните это со строковым объектом в Java:
Экземпляр строки (кусок памяти, содержащий символы «H», «e», «l», «l» и «o») не может быть изменен; Я не могу изменить содержимое этой строки. Когда ты пишешь что-то вроде
вы не добавляете "World" в конец экземпляра "Hello"; Вы создаете новый экземпляр , копируете в него «Hello World» и обновляете
foo
его, ссылаясь на этот новый экземпляр строки.foo
не содержит сам экземпляр строки; он относится только к этому экземпляру (аналогично указателю в C или Obj-C), поэтому типы типа String называются ссылочными типами.источник