Что такое неизменность и почему я должен волноваться об этом?

Замечание о выпуске Xcode9 beta2:

Jpeg-активы в каталогах активов не найдены в iOS 10 или более ранних версиях для приложений, созданных с помощью Xcode 9. API-файлы для доступа к изображению, такие как UIImage.imageNamed: return ноль. (32524123)

Временное решение: используйте ресурсы png или ограничьте тестирование приложений на устройствах с iOS 11 или более поздней версией.

Xcode9 beta3 примечание к выпуску:

Jpeg-активы в каталогах активов находятся в iOS 10 или более ранних версиях для приложений, созданных с помощью Xcode 9. (32524123)

56
задан David Pokluda 7 March 2009 в 23:47
поделиться

13 ответов

Что такое Неизменность?

  • Неизменность применяется, прежде всего, к объектам (строки, массивы, пользовательский класс Животных)
  • Как правило, если существует неизменная версия класса, изменяемая версия также доступна. Например, Objective C и Какао определяют и (неизменный) класс NSString и класс NSMutableString.
  • , Если объект неизменен, он не может быть изменен после того, как он создается (в основном только для чтения). Вы могли думать о нем как, "только конструктор может изменить объект".

Это непосредственно не имеет никакого отношения к вводу данных пользователем; даже Ваш код не может изменить значение неизменного объекта. Однако можно всегда создавать новый неизменный объект заменить его. Вот псевдопример кода; обратите внимание, что на многих языках можно просто сделать myString = "hello"; вместо того, чтобы использовать конструктора, как я сделал ниже, но я включал его для ясности:

String myString = new ImmutableString("hello");
myString.appendString(" world"); // Can't do this
myString.setValue("hello world"); // Can't do this
myString = new ImmutableString("hello world"); // OK

Вы упоминаете "объект, который просто возвращает информацию"; это автоматически не делает это хорошим кандидатом на неизменность. Неизменные объекты имеют тенденцию всегда возвращать то же значение, с которым они были созданы, таким образом, я склонен сказать, что текущее время не было бы идеально, так как это часто изменяется. Однако у Вас мог быть класс MomentOfTime, который создается с определенной меткой времени и всегда возвращает ту одну метку времени в будущем.

Преимущества Immutabilty

  • при передаче объекта другой функции/методу Вам не придется волноваться о том, будет ли тот объект иметь то же значение после функциональных возвратов. Например:

    String myString = "HeLLo WoRLd";
    String lowercasedString = lowercase(myString);
    print myString + " was converted to " + lowercasedString;
    

    , Что, если реализация lowercase() изменила myString, поскольку это создавало строчную версию? Третья строка не дала бы Вам результат, который Вы хотели. Конечно, польза lowercase() функция не сделала бы этого, но Вам гарантируют этот факт, если myString будет неизменен. По сути, неизменные объекты могут помочь осуществить хорошие методы объектно-ориентированного программирования.

  • легче сделать неизменный объект ориентированным на многопотоковое исполнение

  • , Это потенциально упрощает реализацию класса (хороший, если Вы - тот, пишущий класс)

состояние

, Если бы необходимо было взять все переменные экземпляра объекта и записать их значения на бумаге, которая была бы состоянием того объекта в тот данный момент. Состояние программы является состоянием всех своих объектов в данный момент. Изменения состояния быстро со временем; программа должна изменить состояние, чтобы продолжить работать.

Неизменные объекты, однако, фиксировали состояние со временем. После того, как созданный, состояние неизменного объекта не изменяется, хотя состояние программы в целом могло бы. Это помогает отслеживать то, что происходит (и посмотрите другие преимущества выше).

57
ответ дан PCheese 7 November 2019 в 16:42
поделиться

Посмотрите, я не прочитал ссылки, которые Вы отправили.

Однако вот мое понимание.
Каждая программа содержит некоторое знание, он - данные (состояние), которое может изменить любого изменениями ввода данных пользователем / внешними изменениями и т.д.

Переменные (значения, которые изменяются), сведены, поддерживают состояние. Неизменный означает некоторые данные, которые не изменяются. Можно сказать, это - то же как только для чтения или постоянное в некотором роде (это видно он тот путь).

AFAIK, функциональное программирование имеет неизменные вещи (т.е. Вы не можете использовать присвоение на переменную, содержащую значение. То, что можно сделать, создают другую переменную, которая может содержать исходное значение + изменения).

.NET имеет строковый класс, который является примером.
т.е. Вы не можете изменить строку в ее месте

строка s = "привет"; я могу записать s. Замена ("el", "a"); Но это не изменит содержание переменной s.

то, Что я могу сделать, является s = s. Замена ("el", "a");
Это создаст новую переменную & присвойте его значение s (перезаписывающий содержание s).

Эксперты могут исправить ошибки, если я имею в моем понимании.

РЕДАКТИРОВАНИЕ: Неизменный = Не могущий быть переданным, как только это содержит некоторое значение & не может быть заменен на месте (возможно?)

0
ответ дан shahkalpesh 7 November 2019 в 16:42
поделиться

"..., почему я должен волноваться об этом?"

А практическим примером является повторяющаяся конкатенация строк. В.NET, например:

string SlowStringAppend(string [] files)
{
    // Declare an string
    string result="";

    for (int i=0;i<files.length;i++)
    {
        // result is a completely new string equal to itself plus the content of the new
        // file
        result = result + File.ReadAllText(files[i]);
    }

    return result;
}    

string EfficientStringAppend(string [] files)
{
    // Stringbuilder manages a internal data buffer that will only be expanded when absolutely necessary
    StringBuilder result=new SringBuilder();

    for (int i=0;i<files.length;i++)
    {
        // The pre-allocated buffer (result) is appended to with the new string 
        // and only expands when necessary.  It doubles in size each expansion
        // so need for allocations become less common as it grows in size. 
        result.Append(File.ReadAllText(files[i]));
    }

    return result.ToString();
}

, К сожалению, использование первого (медленного) функционального подхода является все еще наиболее часто используемым. Понимание неизменности делает это очень ясным, почему использование StringBuilder так важно.

1
ответ дан Ash 7 November 2019 в 16:42
поделиться

Неизменный объект - что-то, что можно безопасно принять, не собирается изменяться; это имеет важное свойство, что все использующие его могут предположить, что видят то же значение.

Неизменность обычно также означает, что можно думать об объекте, как являющемся "значением", и что нет никакого эффективного различия между идентичными копиями объекта и самого объекта.

2
ответ дан MandyK 7 November 2019 в 16:42
поделиться

Хороший вопрос.

Многопоточность. Если все типы неизменны тогда, условия состязания не существуют, и Вы в безопасности бросить столько потоков в код, сколько Вы желаете.

, Очевидно, Вы не можете выполнить так много без переменчивости, сохраняют сложные вычисления, таким образом, Вам обычно нужна некоторая переменчивость для создания функционального программного обеспечения для бизнеса. Однако стоит распознать, где неизменность должна лечь, такие как что-либо транзакционное.

Ищут функциональное программирование и понятие чистоты для получения дополнительной информации о философии. Чем больше Вы храните на стеке вызовов (параметрические усилители, Вы являетесь передающими к методам) в противоположность предоставлению доступа к ним через ссылки, такие как наборы или статически доступные объекты, тем более чиста Ваша программа и менее подверженное условиям состязания, которыми Вы будете. С большим количеством мультиядер в эти дни эта тема более важна.

Также неизменность уменьшает сумму возможностей в программе, которая уменьшает потенциальную сложность и потенциал для ошибок.

3
ответ дан Quibblesome 7 November 2019 в 16:42
поделиться

Вы не можете изменить неизменный объект, поэтому необходимо заменить его...., "для изменения его". т.е. замена тогда отбрасывает. "Замена" в этом смысле означает изменять указатель от одной ячейки памяти (старого значения) другому (для нового значения).

Примечание, что при этом мы теперь использование дополнительной памяти. Некоторые для старого значения, некоторые для нового значения. Также отметьте, некоторые люди запутываются, потому что они смотрят на код, такой как:

string mystring = "inital value";
mystring = "new value";
System.Console.WriteLine(mystring); // Outputs "new value";

и думают себе, "но я изменяю его, посмотрите тут же в черно-белых тонах! выводы mystring 'новое значение'...... Я думал, что Вы сказали, что я не мог изменить его?!!"

, Но на самом деле под капотом, что происходит, это выделение новой памяти, т.е. mystring теперь указывает на другой адрес памяти и пространство. "Неизменный" в этом смысле, не посылает к значению mystring, а скорее памяти, используемой переменной mystring сохранить ее значение.

На определенных языках память, хранящая старое значение, должна быть вручную очищена, т.е. программист должен явно выпустить его..... и не забыть делать так. На других языках это - автоматическая функция языка т.е. сборки "мусора" в .NET.

Одно из мест это действительно прорывается, re:memory использование находится в очень итерационных циклах, особенно со строками как в сообщении Пепла. Скажите создание страницы HTML в итерационном цикле где Вы постоянно добавляли следующий блок HTML к последнему и, только для ударов, Вы делали это на сервере большого объема. Это постоянное выделение "новой памяти значения" может быстро стать дорогим, и в конечном счете фатальным, если "старая память значения", правильно не очищена.

Другая проблема состоит в том, что некоторые люди предполагают, что вещи как сборка "мусора" (GC) сразу происходят. Но это не делает. Существует различная оптимизация, которая происходит таким образом, что сборка "мусора" установлена произойти в течение более периодов неактивности. Таким образом, может быть значительная задержка между тем, когда память отмечена, как отброшено и когда она на самом деле освобождена сборщиком "мусора"...., таким образом, можно перенести скачки использования памяти большой емкости при простой задержке проблемы к GC.

, Если GC не получает шанс работать, прежде чем у Вас закончится память, затем вещи, как которые обязательно падает привычка на других языках, которые не имеют автоматической сборки "мусора". Вместо этого GC умрет как самый высокий приоритетный процесс к свободному отброшенная память, неважно, как плохо синхронизация, и становится процессом блокирования, в то время как это очищает вещи. Очевидно, это не прохладно.

Так в основном, необходимо кодировать с этими вещами в памяти и изучить документацию для языков, которые Вы используете для лучших методов/шаблонов, которые позволяют Вам избегать/смягчать этого риска.

Как в сообщении Пепла, в .NET и со строками, методические рекомендации состоят в том, чтобы использовать изменяемый класс StringBuilder, а не неизменные строковые классы когда дело доходит до потребности постоянно изменить строковое значение.

Другие языки/типы будут так же иметь свои собственные обходные решения.

1
ответ дан rism 7 November 2019 в 16:42
поделиться

Позвольте мне добавить еще одну вещь. Кроме того, все, что было упомянуто выше Вас также, хочет неизменность для:

2
ответ дан Community 7 November 2019 в 16:42
поделиться

Помещать его простой: Как только Вы создаете неизменный объект, нет никакого способа изменить содержание того объекта. Примерами .NET неизменные объекты является String и Uri.

при изменении строки Вы просто получаете новую строку. Исходная строка не изменится. Uri имеет только свойства только для чтения и никакие методы, доступные для изменения содержания Uri.

Случаи, что неизменные объекты важны, являются различными, и в большинстве случаев имеют отношение к безопасности. Uri является хорошим примером здесь. (например, Вы не хотите, чтобы Uri был изменен некоторым недоверяемым кодом.) Это означает, что можно передать ссылку на неизменный объект вокруг, не имея необходимость волноваться, что содержание будет когда-либо изменяться.

Hope это помогает.

8
ответ дан Jeroen Landheer 7 November 2019 в 16:42
поделиться

Вещи, которые неизменны, никогда не изменяются. Изменяемые вещи могут измениться. Изменяемые вещи видоизменяются. Неизменные вещи, кажется, изменяют, но на самом деле создают новую изменяемую вещь.

, Например, вот карта в Clojure

(def imap {1 "1" 2 "2"})
(conj imap [3 "3"])
(println imap)

, первая строка создает новую неизменную карту Clojure. Вторая строка соединяется 3 и "3" к карте. Это может появиться, как будто это изменяет старую карту, но в действительности это возвращается новый карта с 3 "3" добавленных. Это - главный пример неизменности. Если бы это было изменяемой картой, то она просто добавила бы 3 "3" непосредственно к та же старая карта. Третья печать строки карта

{3 "3", 1 "1", 2 "2"}

Неизменность помогает содержать код в чистоте и безопасный. Это и другие причины - то, почему языки функционального программирования имеют тенденцию склоняться к неизменности и менее с сохранением информации.

6
ответ дан Rayne 7 November 2019 в 16:42
поделиться

Неизменность

Проще говоря, память неизменна, когда она не изменяется, будучи инициализированным.

Программы, записанные на императивных языках, таких как C, Java и C#, могут управлять данными в оперативной памяти по желанию. Область физической памяти, когда-то отложенной, может быть изменена полностью или часть потоком выполнения в любое время во время осуществления программы. На самом деле императивные языки поощряют этот способ запрограммировать.

программы Записи таким образом было невероятно успешно для однопоточных приложений. Однако, поскольку современная разработка приложений двигает несколько параллельных потоков операции в рамках единственного процесса, мир потенциальных проблем и сложности представлен.

, Когда существует только один поток выполнения, можно предположить, что этот единственный поток 'владеет' всеми данными в памяти и поэтому может управлять ею по желанию. Однако нет никакого неявного понятия владения, когда несколько выполняющихся потоков включены.

Вместо этого эта нагрузка падает на программиста, который должен пойти на многое, чтобы гарантировать, что структуры в оперативной памяти находятся в согласованном состоянии для всех читателей. Блокировка конструкций должна использоваться в осторожной мере, чтобы мешать одному потоку видеть данные, в то время как это обновляется другим потоком. Без этой координации поток неизбежно использовал бы данные, которые были только промежуточными посредством того, чтобы быть обновленным. Результат от такой ситуации является непредсказуемым и часто катастрофическим. Кроме того, создание блокирующий работу правильно в коде является известно трудным и при имении проблемы может нанести вред производительности или, в худшем случае, мертвые блокировки случая то выполнение останова необратимо.

Используя неизменные структуры данных облегчает потребность ввести сложную блокировку в код. Когда раздел памяти, как гарантируют, не изменится в течение времени жизни программы тогда, несколько читателей могут получить доступ к памяти одновременно. Для них не возможно заметить что конкретные данные в непоследовательном состоянии.

Много языков функционального программирования, таких как Lisp, Haskell, Erlang, F# и Clojure, поощряют неизменные структуры данных по самой своей природе. Именно по этой причине они наслаждаются всплеском интереса, поскольку мы двигаем все больше сложную многопоточную разработку приложений и много-компьютерные архитектуры ЭВМ.

состояние

состояние приложения может просто считаться содержанием всей памяти и регистров ЦП в определенный момент времени.

Логически, состояние программы может быть разделено на два:

  1. состояние "кучи"
  2. состояние стопки каждого потока выполнения

В управляемых средах, таких как C# и Java, один поток не может получить доступ к памяти другого. Поэтому каждый поток 'владеет' состоянием своего стека. Стек может считаться содержащий локальные переменные и параметры типа (struct) значения и ссылки на объекты. Эти значения изолируются от внешних потоков.

Однако данные по "куче" совместно используемы среди всех потоков, следовательно заботьтесь, должен быть взят для управления параллельным доступом. Весь ссылочный тип (class) экземпляры объектов хранится на "куче".

В ООП, состояние экземпляра класса определяется его полями. Эти поля хранятся на "куче" и так доступны от всех потоков. Если класс определяет методы, которые позволяют полям быть измененными после того, как конструктор завершается, то класс изменяем (не неизменный). Если поля не могут быть изменены всегда, то тип неизменен. Важно отметить, что класс со всеми полями C# readonly / Java final не обязательно неизменен. Эти конструкции удостоверяются , ссылка не может измениться, но не ссылочный объект. Например, поле может иметь неизменную ссылку на список объектов, но фактическое содержание списка может быть изменено в любое время.

Путем определения типа, как являющегося действительно неизменным, его состояние можно считать замороженным, и поэтому тип безопасен для доступа несколькими потоками.

На практике, это может быть неудобно для определения всех типов как неизменных. Для изменения, значение на неизменном типе может включить маленькое копирование памяти. Некоторые языки делают этот процесс легче, чем другие, но так или иначе ЦП закончит тем, что делал некоторую дополнительную работу. Много факторов способствуют, чтобы определить, перевешивает ли время, проведенное копирование памяти, влияние блокировки конкуренций.

Большое исследование вошло в разработку неизменных структур данных, таких как списки и деревья. При использовании таких структур, скажем список, 'добавить' операция возвратит ссылку на новый список с новым добавленным объектом. Ссылки на предыдущий список не видят изменения и все еще имеют последовательное представление данных.

20
ответ дан Drew Noakes 7 November 2019 в 16:42
поделиться

Создание неизменных вещей предотвращает большое количество частых ошибок.

, Например, у Студента никогда не должно быть их студенческого изменения # на них. Если Вы не позволяете устанавливать переменную (и делать ее константой или финалом, или безотносительно Ваших поддержек языка) тогда, можно осуществить это во время компиляции.

, Если вещи изменяемы и Вы не хотите, чтобы они изменились, при передаче их вокруг Вас, должен сделать защитную копию, которую Вы передаете. Тогда, если метод/функция, Вы называете изменения копией объекта оригинал, является нетронутым.

неизменные вещи Создания означают, что Вы не должны помнить (или занять время/память) сделать защитные копии.

, Если Вы действительно работаете в нем и думаете о каждой переменной, что делаете, Вы найдете, что подавляющее большинство (у меня обычно есть 90-95%) Ваших переменных, никогда не изменяются, как только им дают значение. Выполнение этого делает программы легче следовать и сокращает количество ошибок.

Для ответа на вопрос на состоянии состояние является значениями, которые имеют переменные "объекта" (быть, что класс или структура). Если бы Вы взяли состояние "объекта" человека, то были бы вещи как цвет глаз, цвет волос, длина волос, и т.д.... некоторые из тех (скажите, что цвет глаз), не изменяются, в то время как другие, такие как длина волос действительно изменяются.

1
ответ дан TofuBeer 7 November 2019 в 16:42
поделиться

Пример потенциальных выигрышей в производительности, предлагаемых неизменными объектами, доступен в API WPF. Общий базовый класс многих типов WPF Freezable.

Несколько примеров WPF предполагают, что замораживание объектов (делающий их неизменный во времени выполнения) может значительно улучшить производительность приложения как блокировку, и копирование не требуется.

Лично мне жаль, что понятие неизменности не было легче выразить на языке, который я чаще всего использую, C#. Существует readonly модификатор, доступный для полей. Я хотел бы видеть readonly модификатор на типах также, которые будут только позволены для типов, которые только имеют поля только для чтения, которые имеют типы только для чтения. По существу это означает, что все состояние должно было бы быть введено во время создания, и что и весь граф объектов будет заморожен. Я предполагаю, что были эти метаданные, внутренние CLR тогда, это могло легко использоваться для оптимизации анализа мусора для GC.

0
ответ дан Drew Noakes 7 November 2019 в 16:42
поделиться

Sorry, why does immutability prevent race conditions (in this example, write after read hazards)?

shared v = Integer(3)
v = Integer(v.value() + 1) # in parallel
0
ответ дан gatoatigrado 26 November 2019 в 17:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: