В объектно-ориентированном и функциональном программировании неизменяемый объект (unchangeable [1] объект) - это объект , состояние которого не может быть изменено после его создания. [2] В этом отличие от изменяемого объекта (изменяемого объекта), который может быть изменен после его создания. [3] В некоторых случаях объект считается неизменным, даже если некоторые внутренние атрибуты меняются, но состояние объекта кажется неизменным с внешней точки зрения. Например, объект, который использует мемоизацию для кэширования результатов дорогостоящих вычислений, все еще может считаться неизменяемым объектом.
Строки и другие конкретные объекты обычно выражаются как неизменяемые объекты, чтобы улучшить читаемость и эффективность выполнения в объектно-ориентированном программировании . Неизменяемые объекты также полезны, потому что они по своей природе потокобезопасны . [2] Другие преимущества заключаются в том, что они проще для понимания и рассуждений, а также обеспечивают более высокий уровень безопасности, чем изменяемые объекты. [2]
Концепции
Неизменяемые переменные
В императивном программировании значения, хранящиеся в переменных программы , содержимое которых никогда не изменяется, называются константами, чтобы отличать их от переменных, которые могут быть изменены во время выполнения. Примеры включают коэффициенты преобразования из метров в футы или значение числа пи с точностью до нескольких десятичных знаков.
Поля только для чтения могут вычисляться при запуске программы (в отличие от констант, которые известны заранее), но никогда не изменяются после их инициализации.
Слабая и сильная неизменность
Иногда говорят о неизменности определенных полей объекта. Это означает, что нет возможности изменить эти части состояния объекта, даже если другие части объекта могут быть изменяемыми ( слабо неизменяемыми ). Если все поля неизменяемы, объект неизменен. Если весь объект не может быть расширен другим классом, объект называется строго неизменяемым . [4] Это могло бы, например, помочь явным образом обеспечить соблюдение определенных инвариантов о том, что определенные данные в объекте остаются неизменными в течение всего времени существования объекта. В некоторых языках это делается с помощью ключевого слова (например, const
в C ++ , final
в Java ), которое обозначает поле как неизменяемое. В некоторых языках это происходит наоборот: в OCaml поля объекта или записи по умолчанию неизменяемы и для этого должны быть явно отмечены значком mutable
.
Ссылки на объекты
В большинстве объектно-ориентированных языков на объекты можно ссылаться . Некоторыми примерами таких языков являются Java , C ++ , C # , VB.NET и многие языки сценариев , такие как Perl , Python и Ruby . В этом случае имеет значение, может ли состояние объекта меняться при совместном использовании объектов через ссылки.
Ссылки и копирование объектов
Если известно, что объект неизменен, рекомендуется создать ссылку на него, а не копировать весь объект. Это сделано для экономии памяти, предотвращая дублирование данных и избегая вызовов конструкторов и деструкторов; это также приводит к потенциальному увеличению скорости выполнения.
Технику копирования ссылок намного сложнее использовать для изменяемых объектов, потому что, если какой-либо пользователь ссылки на изменяемый объект изменяет ее, все другие пользователи этой ссылки видят это изменение. Если это не желаемый эффект, может быть сложно уведомить других пользователей, чтобы они ответили правильно. В таких ситуациях защитное копирование всего объекта, а не ссылки, обычно является простым, но дорогостоящим решением. Шаблон наблюдатель является альтернативным методом для обработки изменений в изменяемые объекты.
Копирование при записи
Копирование при записи (COW) - это метод, сочетающий в себе преимущества изменяемых и неизменяемых объектов и поддерживаемый непосредственно почти всем современным оборудованием . Используя этот метод, когда пользователь просит систему скопировать объект, вместо этого она просто создает новую ссылку, которая по-прежнему указывает на тот же объект. Как только пользователь пытается изменить объект с помощью определенной ссылки, система делает реальную копию, применяет к ней изменения и устанавливает ссылку для ссылки на новую копию. Остальные пользователи не затронуты, потому что они по-прежнему ссылаются на исходный объект. Следовательно, в COW все пользователи имеют изменяемую версию своих объектов, хотя в случае, если пользователи не изменяют свои объекты, сохраняются преимущества неизменяемых объектов в экономии места и скорости. Копирование при записи популярно в системах виртуальной памяти , поскольку позволяет им экономить пространство памяти, при этом правильно обрабатывая все, что может делать прикладная программа.
Интернирование
Практика всегда использования ссылок вместо копий одинаковых объектов известна как интернирование . Если используется интернирование, два объекта считаются равными тогда и только тогда, когда их ссылки, обычно представленные в виде указателей или целых чисел, равны. Некоторые языки делают это автоматически: например, Python автоматически обрабатывает короткие строки . Если алгоритм, реализующий интернирование, гарантированно будет делать это во всех возможных случаях, то сравнение объектов на равенство сводится к сравнению их указателей - существенный выигрыш в скорости в большинстве приложений. (Даже если не гарантируется, что алгоритм будет всеобъемлющим, все же существует возможность быстрого улучшения случая, когда объекты равны и используют одну и ту же ссылку.) Интернирование обычно полезно только для неизменяемых объектов.
Безопасность потоков
Неизменяемые объекты могут быть полезны в многопоточных приложениях. Несколько потоков могут воздействовать на данные, представленные неизменяемыми объектами, не заботясь об изменении данных другими потоками. Поэтому неизменяемые объекты считаются более потокобезопасными, чем изменяемые объекты.
Нарушение неизменности
Неизменяемость не означает, что объект, хранящийся в памяти компьютера, не подлежит перезаписи. Скорее, неизменяемость - это конструкция времени компиляции, которая указывает, что программист может делать через обычный интерфейс объекта, не обязательно то, что он может сделать абсолютно (например, обходя систему типов или нарушая корректность констант в C или C ++ ).
Детали для конкретного языка
В Python , Java и .NET Framework строки являются неизменяемыми объектами. И Java, и .NET Framework имеют изменяемые версии строки. В Java это StringBuffer
и StringBuilder
(изменяемые версии Java String
), а в .NET - это StringBuilder
(изменяемая версия .Net String
). Python 3 имеет изменяемый строковый (байтовый) вариант с именем bytearray
. [5]
Кроме того, все примитивные классы-оболочки в Java неизменяемы.
Аналогичные шаблоны - это неизменяемый интерфейс и неизменяемая оболочка .
В чистых языках функционального программирования невозможно создавать изменяемые объекты без расширения языка (например, через библиотеку изменяемых ссылок или интерфейс внешней функции ), поэтому все объекты неизменяемы.
Ада
В Ada любой объект объявляется либо переменной (т.е. изменяемым; обычно неявное значение по умолчанию), либо constant
(т.е. неизменяемым) с помощью constant
ключевого слова.
тип Some_type - это новое целое число ; - может быть что угодно более сложное x : constant Some_type : = 1 ; - неизменяемый y : Some_type ; - изменчивый
Параметры подпрограмм являются неизменными в в режиме, и изменяемых в в из и из режимов.
процедура Do_it ( a : in Integer ; b : in out Integer ; c : out Integer ) is begin - a неизменяема b : = b + a ; с : = а ; конец Do_it ;
C #
В C # вы можете обеспечить неизменность полей класса с помощью readonly
оператора. Установив все поля как неизменяемые, вы получите неизменяемый тип.
класс AnImmutableType { общественного чтения двойной _value ; общедоступный AnImmutableType ( двойной x ) { _value = x ; } public AnImmutableType Square () { вернуть новый AnImmutableType ( _value * _value ); } }
C ++
В C ++ константно-правильная реализация Cart
позволит пользователю объявлять новые экземпляры класса либо как const
(неизменяемые), либо как изменяемые, по желанию, путем предоставления двух разных версий getItems()
метода. (Обратите внимание, что в C ++ нет необходимости - и фактически невозможно - предоставлять специализированный конструктор для const
экземпляров.)
class Cart { public : Cart ( std :: vector < Item > items ) : items_ ( std :: move ( items )) {} std :: vector < Item > & items () { return items_ ; } const std :: vector < Item > & items () const { return items_ ; } int ComputeTotalCost () const { / * возвращает сумму цен * / } частный : std :: vector < Item > items_ ; };
Обратите внимание, что если есть поле, которое является указателем или ссылкой на другой объект, тогда все еще может быть возможно изменить объект, на который указывает такой указатель или ссылка в константном методе, без нарушения константной корректности. Можно утверждать, что в таком случае объект на самом деле не является неизменным.
C ++ также обеспечивает абстрактную (в отличие от побитовой) неизменяемость с помощью mutable
ключевого слова, которое позволяет изменять переменную-член внутри const
метода.
class Cart { public : Cart ( std :: vector < Item > items ) : items_ ( std :: move ( items )) {} const std :: vector < Item > & items () const { return items_ ; } int ComputeTotalCost () const { если ( total_cost_ ) { return * total_cost_ ; } int total_cost = 0 ; for ( const auto & item : items_ ) { total_cost + = item . Стоимость (); } total_cost_ = total_cost ; вернуть total_cost ; } частный : std :: vector < Item > items_ ; изменяемый std :: optional < int > total_cost_ ; };
D
В D , существует два отборочных типа , const
и immutable
для переменных , которые не могут быть изменены. [6] В отличие от языков C ++ const
, Java final
и C # readonly
, они транзитивны и рекурсивно применяются ко всему, что доступно через ссылки на такую переменную. Разница между const
и immutable
заключается в том, к чему они применяются: const
это свойство переменной: юридически могут существовать изменяемые ссылки на указанное значение, т.е. значение может фактически измениться. Напротив, immutable
это свойство упомянутого значения: значение и все, что транзитивно достижимо из него, не может измениться (без нарушения системы типов, что приводит к неопределенному поведению ). Любая ссылка на это значение должна быть помечена const
или immutable
. В основном для любого неквалифицированного типа T
, const(T)
является объединением непересекающихся T
(изменяемый) и immutable(T)
.
class C { / * изменчивый * / Object mField ; const Object cField ; неизменяемый объект iField ; }
Для изменяемого C
объекта его mField
можно записать. Для const(C)
объекта, mField
не может быть изменен, он наследует const
; iField
остается неизменным, поскольку это более надежная гарантия. Для объекта immutable(C)
все поля неизменяемы.
В такой функции:
void func ( C m , const C c , неизменяемый C i ) { / * внутри фигурных скобок * / }
Внутри фигурных скобок c
может обозначаться тот же объект, что и m
, поэтому мутации m
могут также косвенно изменяться c
. Кроме того, c
может относиться к тому же объекту, что и i
, но, поскольку значение неизменяемо, изменений нет. Однако m
и i
не может юридически относиться к одному и тому же объекту.
На языке гарантий mutable не имеет никаких гарантий (функция может изменить объект), const
является внешней гарантией того, что функция ничего не изменит, и immutable
является двунаправленной гарантией (функция не изменит значение, и вызывающий должен не меняй это).
Значения, которые инициализируются const
или immutable
должны быть инициализированы прямым присваиванием в точке объявления или конструктором .
Поскольку const
параметры забывают, было ли значение изменяемым или нет, аналогичная конструкция inout
, действует, в некотором смысле, как переменная для информации об изменчивости. Функция типа const(S) function(const(T))
возвращает const(S)
типизированные значения для изменяемых, константных и неизменяемых аргументов. Напротив, функция типа inout(S) function(inout(T))
возвращает S
для изменяемых T
аргументов, const(S)
для const(T)
значений и immutable(S)
для immutable(T)
значений.
Приведение неизменяемых значений к изменяемым приводит к неопределенному поведению при изменении, даже если исходное значение происходит из изменяемого источника. Преобразование изменяемых значений в неизменяемые может быть законным, если после этого не останется изменяемых ссылок. «Выражение может быть преобразовано из изменяемого (...) в неизменяемое, если выражение уникально и все выражения, на которые оно транзитивно ссылается, являются уникальными или неизменяемыми». [6] Если компилятор не может доказать уникальность, преобразование может быть выполнено явно, и программист должен убедиться, что не существует изменяемых ссылок.
Тип string
- это псевдоним immutable(char)[]
, то есть типизированный фрагмент памяти неизменяемых символов. [7] Создание подстрок дешево, так как оно просто копирует и изменяет указатель и поле длины, и безопасно, поскольку лежащие в основе данные не могут быть изменены. Объекты типа const(char)[]
могут относиться к строкам, но также и к изменяемым буферам.
Создание неглубокой копии константного или неизменяемого значения удаляет внешний слой неизменяемости: копирование неизменяемой строки ( immutable(char[])
) возвращает строку ( immutable(char)[]
). Неизменяемый указатель и длина копируются, и копии изменяемы. Указанные данные не были скопированы и в этом примере сохраняют свой квалификатор immutable
. Его можно удалить, сделав более глубокую копию, например, используя dup
функцию.
Ява
Классическим примером неизменяемого объекта является экземпляр String
класса Java.
Строка s = "ABC" ; с . toLowerCase ();
Метод toLowerCase()
не изменяет данные, которые s
содержат "ABC" . Вместо этого создается новый объект String, которому во время его создания предоставляются данные «abc». Ссылка на этот объект String возвращается toLowerCase()
методом. Чтобы строка s
содержала данные «abc», необходим другой подход:
s = s . toLowerCase ();
Теперь String s
ссылается на новый объект String, содержащий «abc». В синтаксисе объявления класса String нет ничего, что считало бы его неизменным; скорее, ни один из методов класса String никогда не влияет на данные, содержащиеся в объекте String, что делает его неизменяемым.
Ключевое слово final
( подробная статья ) используется для реализации неизменяемых примитивных типов и ссылок на объекты [8], но само по себе оно не может сделать сами объекты неизменяемыми. См. Примеры ниже:
Примитивный переменные типа ( int
, long
, short
и т.д.) могут быть переназначены после того , как определены. Этого можно избежать, используя final
.
int i = 42 ; // int - это примитивный тип i = 43 ; // ОКфинальный int j = 42 ; j = 43 ; // не компилируется. j является окончательным, поэтому его нельзя переназначить
Ссылочные типы нельзя сделать неизменяемыми с помощью final
ключевого слова. final
только предотвращает переназначение.
последний MyObject m = новый MyObject (); // m имеет ссылочный тип m . данные = 100 ; // ОК. Мы можем изменить состояние объекта m (m является изменяемым, и final не меняет этого факта) m = new MyObject (); // не компилируется. m является окончательным, поэтому не может быть переназначен
Примитивные упаковщики ( Integer
, Long
, Short
, Double
, Float
, Character
, Byte
, Boolean
) также все неизменны. Неизменяемые классы можно реализовать, следуя нескольким простым рекомендациям. [9]
Perl
В Perl можно создать неизменяемый класс с библиотекой Moo, просто объявив все атрибуты только для чтения:
пакет Неизменяемый ; используйте Moo ;has value => ( is => 'ro' , # только для чтения по умолчанию => 'data' , # можно переопределить, задав конструктору # значение: Immutable-> new (value => 'something else'); ) ;1 ;
Для создания неизменяемого класса требовалось два шага: во-первых, создание аксессоров (автоматически или вручную), предотвращающих изменение атрибутов объекта, и, во-вторых, предотвращение прямого изменения данных экземпляра экземпляров этого класса (обычно это хранилось в хеш-коде). ссылку и может быть заблокирован с помощью функции Hash :: Util lock_hash):
пакет Неизменяемый ; используйте строгий ; использовать предупреждения ; использовать базовый qw (Class :: Accessor) ; # создать средства доступа только для чтения __PACKAGE__ -> mk_ro_accessors ( qw (value) ); используйте Hash :: Util 'lock_hash' ;sub новый { мой $ class = shift ; вернуть $ class, если ref ( $ class ); die "Аргументы для нового должны быть пар ключ => значение \ n", если ( @_ % 2 == 0 ); мои % defaults = ( значение => 'данные' , ); мой $ obj = { % по умолчанию , @_ , }; благослови $ obj , $ class ; # запретить модификацию данных объекта lock_hash % $ obj ; } 1 ;
Или с помощью написанного вручную аксессуара:
пакет Неизменяемый ; используйте строгий ; использовать предупреждения ; используйте Hash :: Util 'lock_hash' ;sub новый { мой $ class = shift ; вернуть $ class, если ref ( $ class ); die "Аргументы для нового должны быть пар ключ => значение \ n", если ( @_ % 2 == 0 ); мои % defaults = ( значение => 'данные' , ); мой $ obj = { % по умолчанию , @_ , }; благослови $ obj , $ class ; # запретить модификацию данных объекта lock_hash % $ obj ; }# Только для чтения аксессора югу значения { мой $ самого = сдвиг ; if ( my $ new_value = shift ) { # пытаюсь установить новое значение die "Этот объект нельзя изменить \ n" ; } else { return $ self -> { значение } } } 1 ;
Python
В Python некоторые встроенные типы (числа, логические значения, строки, кортежи, замороженные наборы) неизменяемы, но пользовательские классы обычно изменяемы. Чтобы имитировать неизменяемость в классе, можно переопределить установку и удаление атрибута, чтобы вызвать исключения:
class ImmutablePoint : "" " Неизменяемый класс с двумя атрибутами 'x' и 'y'." "" __slots__ = [ 'x' , 'y' ] def __setattr__ ( self , * args ): raise TypeError ( «Невозможно изменить неизменяемый экземпляр.» ) __delattr__ = __setattr__ def __init__ ( self , x , y ): # Мы больше не можем использовать self.value = value для хранения данных экземпляра # поэтому мы должны явно вызвать суперкласс super () . __setattr__ ( 'x' , x ) super () . __setattr__ ( 'у' , у )
Стандартные помощники библиотеки collections.namedtupleи typing.NamedTuple, доступные начиная с Python 3.6, создают простые неизменяемые классы. Следующий пример примерно эквивалентен приведенному выше, плюс некоторые функции, похожие на кортежи:
от ввода import NamedTuple импортировать коллекцииPoint = коллекции . namedtuple ( 'Точка' , [ 'x' , 'y' ])# следующее создает именованный кортеж, аналогичный указанному выше классу Point ( NamedTuple ): x : int y : int
Представленный в Python 3.7, dataclassesпозволяет разработчикам эмулировать неизменяемость с помощью замороженных экземпляров . Если построен замороженный класс данных, dataclasses
будет переопределен __setattr__()
и __delattr__()
будет повышаться FrozenInstanceError
при вызове.
из классов данных импортировать класс данных@dataclass ( замороженный = True ) класс Точка : x : int y : int
JavaScript
В JavaScript все примитивные типы (Undefined, Null, Boolean, Number, BigInt, String, Symbol) неизменяемы, но пользовательские объекты обычно изменяемы.
function doSomething ( x ) { / * изменение x здесь меняет оригинал? * / }; var str = 'строка' ; var obj = { an : 'объект' }; doSomething ( str ); // строки, числа и типы bool неизменяемы, функция получает копию doSomething ( obj ); // объекты передаются по ссылке и могут изменяться внутри function doAnotherThing ( str , obj ); // `str` не изменилась, но` obj` может измениться.
Чтобы имитировать неизменяемость объекта, можно определить свойства как доступные только для чтения (для записи: false).
var obj = {}; Объект . defineProperty ( obj , 'foo' , { значение : 'bar' , доступно для записи : false }); OBJ . foo = 'bar2' ; // игнорируется молча
Однако описанный выше подход по-прежнему позволяет добавлять новые свойства. В качестве альтернативы можно использовать Object.freeze, чтобы сделать существующие объекты неизменяемыми.
var obj = { foo : 'bar' }; Объект . заморозить ( obj ); OBJ . foo = 'бары' ; // не может редактировать свойство, игнорируется obj . foo2 = 'bar2' ; // невозможно добавить свойство, игнорируется молча
С реализацией ECMA262 JavaScript имеет возможность создавать неизменяемые ссылки, которые нельзя переназначить. Однако использование const
объявления не означает, что значение ссылки только для чтения является неизменным, просто имя не может быть присвоено новому значению.
const ALWAYS_IMMUTABLE = истина ;попробуйте { ALWAYS_IMMUTABLE = false ; } catch ( err ) { console . log ( "Невозможно переназначить неизменяемую ссылку." ); }const arr = [ 1 , 2 , 3 ]; обр . толкать ( 4 ); консоль . журнал ( обр ); // [1, 2, 3, 4]
Использование неизменяемого состояния стало растущей тенденцией в JavaScript с момента появления React , который отдает предпочтение шаблонам управления состоянием, подобным Flux, таким как Redux . [10]
Ракетка
Racket существенно отличается от других реализаций Схемы , делая свой тип базовой пары ("cons-ячейки") неизменяемым. Вместо этого, он обеспечивает параллельный изменяемый тип пару, с помощью mcons
, mcar
, и set-mcar!
т.д. Кроме того, многие неизменные типов поддерживаемых, например, неизменных строк и векторов, и они широко используются. Новые структуры неизменяемы по умолчанию, если только поле специально не объявлено изменяемым, или вся структура:
( struct foo1 ( x y )) ; все поля неизменяемы ( struct foo2 ( x [ y #: mutable ])) ; одно изменяемое поле ( struct foo3 ( x y ) #: mutable ) ; все поля изменяемы
Язык также поддерживает неизменяемые хэш-таблицы, реализованные функционально, и неизменяемые словари.
Ржавчина
Система владения Rust позволяет разработчикам объявлять неизменяемые переменные и передавать неизменяемые ссылки. По умолчанию все переменные и ссылки неизменяемы. Изменяемые переменные и ссылки явно создаются с помощью mut
ключевого слова.
Постоянные элементы в Rust всегда неизменяемы.
// постоянные элементы всегда неизменяемы const ALWAYS_IMMUTABLE : bool = true ; struct Object { х : использовать , y : usize ,}fn main () { // явно объявить изменяемую переменную let mut mutable_obj = Object { x : 1 , y : 2 }; mutable_obj . х = 3 ; // хорошо пусть mutable_ref = & mut mutable_obj ; mutable_ref . х = 1 ; // хорошо пусть immutable_ref = & mutable_obj ; immutable_ref . х = 3 ; // ошибка E0594 // по умолчанию переменные неизменяемы let immutable_obj = Object { x : 4 , y : 5 }; immutable_obj . х = 6 ; // ошибка E0596 let mutable_ref2 = & mut immutable_obj ; // ошибка E0596 пусть immutable_ref2 = & immutable_obj ; immutable_ref2 . х = 6 ; // ошибка E0594 }
Scala
В Scala любую сущность (узко, привязку) можно определить как изменяемую или неизменяемую: в объявлении можно использовать val
(значение) для неизменяемых сущностей и var
(переменную) для изменяемых. Обратите внимание, что даже несмотря на то, что неизменяемая привязка не может быть переназначена, она по-прежнему может относиться к изменяемому объекту, и по-прежнему можно вызывать изменяющие методы для этого объекта: привязка неизменна, но базовый объект может быть изменяемым.
Например, следующий фрагмент кода:
значение maxValue = 100 var currentValue = 1
определяет неизменяемую сущность maxValue
(целочисленный тип определяется во время компиляции) и изменяемую сущность с именем currentValue
.
По умолчанию классы коллекций, такие как List
и, Map
являются неизменяемыми, поэтому методы обновления возвращают новый экземпляр, а не изменяют существующий. Хотя это может показаться неэффективным, реализация этих классов и их гарантии неизменности означают, что новый экземпляр может повторно использовать существующие узлы, что, особенно в случае создания копий, очень эффективно. [11] [ нужен лучший источник ]
Смотрите также
- Clojure
- Erlang
- F #
- Haskell
- Пролог
- Tcl
- Scala
- Мутаторный метод
Рекомендации
Эта статья содержит некоторые материалы из книги Perl Design Patterns Book.
- ^ «неизменное прилагательное - Определение, изображения, произношение и примечания по использованию - Оксфордский словарь для продвинутых учащихся на OxfordLearnersDictionaries.com» . www.oxfordlearnersictionaries.com .
- ^ a b c Goetz et al. Параллелизм Java на практике . Addison Wesley Professional, 2006, раздел 3.4. Неизменность
- ^ «6.005 - Разработка программного обеспечения» .
- ^ Дэвид О'Мира (апрель 2003 г.). «Изменяемые и неизменяемые объекты: убедитесь, что методы нельзя переопределить» . Ранчо Ява . Проверено 14 мая 2012 .
Предпочтительный способ - сделать класс финальным. Иногда это называют «строгой неизменяемостью». Это не позволяет кому-либо расширять ваш класс и случайно или намеренно сделать его изменяемым.
- ^ «Встроенные функции - документация Python v3.0» . docs.python.org .
- ^ a b D Спецификация языка § 18
- ^ D Спецификация языка § 12.16 (Термины массив и срез используются как синонимы.)
- ^ «Как создать неизменяемый класс и объект в Java - учебный пример» . Javarevisited.blogspot.co.uk. 2013-03-04 . Проверено 14 апреля 2014 .
- ^ «Неизменяемые объекты» . javapractices.com . Проверено 15 ноября 2012 года .
- ^ «Неизменяемость в JavaScript: противоположная точка зрения» . Desalasworks .
- ^ «API коллекций Scala 2.8 - конкретные неизменяемые классы коллекций» . Scala-lang.org . Проверено 14 апреля 2014 .
Внешние ссылки
- Неизменяемые объекты в C # за 3 простых шага.
- Статья Теория и практика Java: видоизменять или не видоизменять? по Брайан Гетц , от IBM DeveloperWorks - Сохраненная копия в Интернет Архиве по Брайан Гетц , от IBM DeveloperWorks - Сохраненная копия в Интернет Архиве
- Неизменяемые объекты из JavaPractices.com
- Неизменяемые объекты из Портлендского репозитория паттернов
- Immutable.js от Facebook
- Неизменяемые структуры в проекте C # с открытым исходным кодом в Codeplex
- Неизменяемые коллекции в официальной библиотеке .NET от Microsoft
- Неизменяемые объекты в C # от Tutlane.com