Разница между неизменным и постоянным

28

Я часто видел термины immutableи constиспользовал их взаимозаменяемо. Однако, из моего (небольшого) опыта, они сильно отличаются по «контракту», который они заключают в коде:

Immutable заключает договор о том, что этот объект не изменится (например, кортежи Python, строки Java).

Const заключает договор о том, что в области действия этой переменной она не будет изменена (никаких обещаний относительно того, что другие потоки могут сделать с объектом, на который указывает этот период, например, с ключевым словом C / C ++).

Очевидно, что они не эквивалентны, если только язык не является однопоточным (PHP) или не имеет линейной или уникальной системы ввода (Clean, Mercury, ATS).

Во-первых, верно ли мое понимание этих двух понятий?

Во-вторых, если есть разница, почему они почти исключительно используются взаимозаменяемо?

K.Steff
источник
1
constне существует в каждом языке, а изменчивость и неизменность не существуют в каждом языке, поэтому использование этого языка в качестве агониста не применимо. Это язык конкретных только там , где применяются эти понятия.
2
Связанное, рекомендуемое чтение: Виды неизменности (несколько примеров на C #, но в основном не зависящих от языка). Кто-то наградит Эрика Липперта медалью.

Ответы:

14

Я поговорю с C ++, где эта разница наиболее актуальна.

Как вы правильно заметили, неизменность означает, что объект не может измениться вообще после его создания. Это создание может, конечно, происходить во время выполнения, т. Е. constОбъект не обязательно является константой времени компиляции. В C ++ объект является неизменным, если встречаются (1) и (2) или (3):

  1. У него нет членов, объявленных mutableмутированными constфункциями

  2. Объявлено const

  3. constфункции-члены не используют const_castдля удаления constквалификации, чтобы изменить членов

Однако вы могли бы также рассмотреть модификаторы доступа: если операция внутренне мутирует экземпляр, но не влияет на состояние экземпляра, наблюдаемого через его открытый интерфейс, то объект «логически неизменен».

Таким образом, C ++ предоставляет инструменты, необходимые для создания неизменяемых объектов, но, как и большинство всего в C ++, инструменты минимально достаточны и требуют реального усердия для реального использования. Состояние экземпляра не обязательно ограничено переменными-членами экземпляра - поскольку C ++ не обеспечивает способ обеспечения ссылочной прозрачности, он может также включать глобальное состояние или состояние класса.

constтакже имеет другую функцию в C ++: квалифицировать ссылки и указатели. constСсылка может относиться к не- constобъекта. Разрешается (хотя и не всегда необходимо или целесообразно) использовать const_castдля изменения объекта посредством constссылки, если и только если этот объект объявлен как не const:

int        i = 4;         // Non-const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Legal.

И, конечно, это неопределенное поведение, чтобы изменить constобъект:

const int  i = 4;         // const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Illegal.
Джон Перди
источник
19

Говоря о Java, где ключевое слово «final» представляет «const», рассмотрим:

final Person someone = new Person();

Это означает, что someoneНИКОГДА не может ссылаться на другой объект Person. Но вы все равно можете изменить данные о человеке, которого направляют. Напримерsomeone.setMonthlySalary(10000);

Но, если бы это someoneбыл «неизменяемый» объект, было бы верно одно из следующих действий: (a) у вас не было бы метода с именем setMonthlySalary (b) вызов setMonthlySalary всегда вызывал бы исключение, такое какUnsupportedOperationException

rationalrevolt
источник
10

Неизменяемыми объектами являются те, которые не изменяют состояние после его создания. Например;

string prefix = "Pre";
string postfix = "Post";
string myComplexStr = prefix + postfix;

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

Const-объекты обычно используются для идентификации некоторых реальных констант, значения которых известны до компиляции, таких как Pi, "USA", "StackOverflow.com", номера портов и так далее.

С этой точки зрения Const отличается от неизменяемых объектов, потому что их значения не рассчитываются программой.

Но если вы говорите о ключевом слове «const» в C ++, вы можете сказать, что «const» используется для создания неизменяемых объектов.

Мерт Акчакая
источник
1
const в C ++ не создает неизменных объектов, это всего лишь уровень доступа.
Klaim
Можете ли вы объяснить, как «const double pi = 3.14» не является неизменным?
Мерт Акчакая
Ну, это зависит от того, где это. Допустим, я делаю: «double * p_pi = const_cast <double *> (& pi); * p_pi = 42;» например. Затем, если pi находится в глобальном пространстве или пространстве имен, я получаю ошибку сегментации, но это, я считаю, неопределенное поведение, а не конкретная ошибка. Если pi является членом какого-либо объекта, который доступен во время выполнения и не является статичным, я получаю pi == 42. Видите ли, даже использование mutable доступно, потому что const в C ++ имеет отношение к уровню доступа, семантическую, а не неизменность данных, что почти невозможно достичь в C ++. Вы можете только "симулировать" это. const не является неизменным.
Klaim
1
@ Klaim Отключение constподобного поведения - неопределенное поведение, независимо от того, где оно размещено, IIRC. А неопределенное поведение хуже любой конкретной ошибки, которая гарантированно произойдет. Это означает, что вы больше не используете C ++ - C ++ не предоставляет средств для изменения constзначения (за исключением mutableчленов, конечно, но это не ваша точка зрения), поэтому, что касается C ++, вы не можете это сделать. Какие конкретные реализации позволяют разрешить - это совсем другой вопрос (и, держу пари, если вы компилируете с оптимизацией, трюк, который вы потянули, не повлияет на последующие выражения, piпотому что он был заменен).
«const в C ++ не создает неизменных объектов» по-прежнему неверно, потому что он по-прежнему создает глобальные константы, как вы указали в своем ответе. Ключевое слово, конечно, семантическое на некотором уровне, в противном случае вы всегда можете просто вручную изменить напряжение ячейки памяти и изменить значение неизменяемого объекта, если вы так стремитесь даже использовать неопределенное поведение.
Мерт Акчакая
8

Во-первых, верно ли мое понимание этих двух понятий?

Да, но ваш второй вопрос показывает, что вы не понимаете этих различий.

Во-вторых, если есть разница, почему они почти исключительно используются взаимозаменяемо?

constв C ++ используется только для уровня доступа (это означает «только для чтения») , а не для неизменности. Это означает, что сам доступ полностью отделен от данных. Например, вы можете манипулировать некоторыми данными, а затем предоставлять их через константную ссылку. Доступ только для чтения, но сами данные, как и все данные, являются изменчивыми.

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

Теперь вы можете смоделировать неизменность в C ++, убедившись, что к некоторым данным нельзя получить доступ каким-либо иным способом, кроме const, и убедитесь, что они инициализированы, а затем не затрагиваются. Но это не является надежной гарантией, поскольку такие языки, как D, дают вам, когда вы помечаете свои данные как неизменные. Язык гарантирует, что вообще невозможно выполнять какие-либо операции, модифицирующие эти данные, в то время как в C ++ вы все еще потенциально можете изменять данные с помощью константного преобразования и изменчивости, если это действительно необходимо.

В конце концов, это совсем не то же самое, что и вовсе не дает одинаковых гарантий.

Klaim
источник
3

Говоря о JavaScript, ключевые слова constиObject.freeze

constотносится к привязкамvariables . Это создает неизменную привязку, вы не можете присвоить ей новое значение.

Object.freezeработает над значениями объекта. Это делает объект неизменным . А именно, вы не можете изменить его свойства.

zangw
источник
0

В C ++ они одинаковы. Хотя вы можете изменить constобъект, если у вас есть его расположение в памяти и разрешение ОС для записи в эту память.

Мартин Беккет
источник
1
На самом деле это аргумент против того, что они одинаковы: C ++ просто не имеет неизменного ключевого слова или языковой поддержки. Кроме того, я предполагаю, что программист использует язык разумным образом: в противном случае const тоже не имеет абсолютно никакого значения.
К.Стефф
1
@ K.Steff - возможно, лучше сказать, что в C ++ нет дополнительной неизменности, кроме как предоставленной const
Martin Beckett
Абсолютно точно :)
K.Steff
В C ++ они не одинаковы вообще. const - это уровень доступа «только для чтения», это не значит, что данные неизменны. Вы можете обойти это в C ++, большую часть времени.
Klaim
0

В C, C ++ и связанных языках также существует разница между объектом const и вашей ссылкой или указателем на объект, являющийся константной ссылкой.

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

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

В C, если вы используете строковый литерал, такой как «Hello», пять символов и завершающие нулевые байты фактически постоянны, но вы получаете неконстантный указатель. Очень плохая идея использовать этот неконстантный указатель для изменения объекта.

В C вы можете иметь указатель «const restrict». Это означает, что объект, на который указывает объект, является временно постоянным. Если объект изменяется любым способом, пока указатель «const restrict» находится в области видимости, вы получите неопределенное поведение. Это сильнее, чем указатель const, который только мешает вам изменить объект через этот указатель.

gnasher729
источник