Різниця між незмінним і const


28

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

Immutable укладає договір про те, що цей об'єкт не змінюватиметься взагалі (наприклад, кортежі Python, рядки Java).

Const укладає договір про те, що в межах цієї змінної він не буде змінений (нічого не обіцяйте щодо того, що інші потоки можуть зробити для об'єкта, на який вказується протягом цього періоду, наприклад, ключового слова C / C ++).

Очевидно, що два не є рівнозначними, якщо мова не є однопоточною (PHP) або не має лінійної або унікальної системи набору тексту (Clean, Mercury, ATS).

По-перше, чи моє розуміння цих двох понять правильне?

По-друге, якщо є різниця, чому вони майже виключно використовуються як взаємозамінні?


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НІКОЛИ не може посилатися на інший об’єкт Особи. Але ви все одно можете змінити дані про особу, яку висилаєте. Напрsomeone.setMonthlySalary(10000);

Але, якби someoneбув об'єкт "Immutable", було б істинно одне з наступного: (a) Ви б не мали методу з назвою setMonthlySalary (b) Calling setMonthlySalary завжди викидав би такий виняток, якUnsupportedOperationException


10

Незмінними об'єктами є ті, які не змінюють стан після його створення. Наприклад;

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

У цьому прикладі об'єкт myComplexStr є незмінним, але не постійним, оскільки його обчислюється значення. І це незмінне, оскільки це рядок і має властивість статичної довжини і не може змінюватися.

Об'єкти Const зазвичай використовуються для ідентифікації деяких реальних констант, значення яких відомі перед компіляцією, наприклад, Pi, "США", "StackOverflow.com", номери портів тощо.

З цього погляду Const відрізняється від об'єктів, що змінюються, оскільки їх значення не обчислюються програмою.

Але якщо ви говорите про ключове слово "const" в C ++, ви можете сказати, що "const" використовується для створення незмінних об'єктів.


1
const в C ++ не створює незмінних об'єктів, це лише рівень доступу.
Клаїм

Чи можете ви пояснити, як "const double pi = 3,14" не є незмінним?
Мерт Аккакая

Ну, це залежить від місця. Скажемо, я роблю: "double * p_pi = const_cast <double>> (& pi); * p_pi = 42;" наприклад. Тоді, якщо pi знаходиться в глобальному просторі чи просторі імен, я отримую помилку сегментації, але це, я вважаю, невизначена поведінка, а не конкретна помилка. Якщо pi є членом будь-якого об'єкта, доступного під час виконання, який не є статичним, я отримую pi == 42. Розумієте, навіть використання мутабельних файлів доступне, оскільки const в C ++ - це рівень доступу, семантичний, а не незмінність даних, майже неможливо досягти в C ++. Ви можете лише «імітувати» його. const не є незмінним.
Клаїм

1
@Klaim Мутація constподібного є невизначеною поведінкою, незалежно від того, де вона виділена, IIRC. І невизначена поведінка гірша за будь-яку конкретну помилку, яка гарантовано трапиться. Це означає, що ви більше не використовуєте C ++ - C ++ не дає можливості змінювати constзначення (крім mutableчленів, звичайно, але це не ваша суть), тому що стосується C ++, ви не можете цього зробити. Яка конкретна реалізація може бути дозволена - це зовсім інша справа (і я обдячу вас, якщо ви компілюєте з оптимізаціями, трюк, який ви витягли, не вплине на пізніші вирази, використовуючи, piоскільки він був заміщений).

"const в C ++ не створює незмінних об'єктів" все ще помиляється, оскільки він все ще створює глобальні константи, як ви заявили у власній відповіді. Ключове слово є звичайно семантичним на певному рівні, інакше завжди можна просто вручну змінити напругу комірки пам’яті та змінити значення незмінного об’єкта, якщо ви так прагнете навіть використовувати невизначені форми поведінки.
Мерт Аккакая

8

По-перше, чи моє розуміння цих двох понять правильне?

Так, але ваше друге питання показує, що ви не розумієте цих відмінностей.

По-друге, якщо є різниця, чому вони майже виключно використовуються як взаємозамінні?

constв C ++ використовується лише для рівня доступу (означає «лише для читання») , а не для незмінності. Це означає, що сам доступ є абсолютно відокремленим від даних. Наприклад, ви можете маніпулювати деякими даними, а потім викривати їх через посилання const. Доступ доступ лише для читання, але самі дані, як і всі дані, можуть змінюватися.

const лише гарантійні обмеження доступу, тоді як незмінність (як, наприклад, D) насправді не передбачає можливості змінити дані на будь-якій стадії життя об'єкта .

Тепер ви можете імітувати незмінність у C ++, переконуючись, що до деяких даних не можна отримати доступ будь-яким іншим способом, ніж const, і переконайтеся, що вони ініціалізовані, а потім більше не торкаються. Але це не є надійною гарантією, оскільки мови, як D, дає вам, коли ви позначаєте свої дані як непорушні. Мова переконайтесь, що взагалі неможливо виконати будь-яку операцію, що модифікує ці дані, тоді як у C ++ ви все ще потенційно можете змінити дані за допомогою const casting та mutability, якщо це дійсно необхідно.

Зрештою, це зовсім не те саме , що він не дає взагалі однакових гарантій.


3

Якщо говорити про JavaScript, ключові слова constтаObject.freeze

constстосується прив’язокvariables . Це створює незмінне зв'язування, ви не можете присвоїти йому нове значення.

Object.freezeпрацює над об'єктними значеннями. Це робить предмет незмінним . А саме, ви не можете змінити його властивості.


0

У С ++ вони однакові. Хоча ви можете змінити constоб'єкт, якщо у вас є його місце в пам'яті та дозвіл ОС для запису в цю пам'ять.


1
Насправді це аргумент проти них однакових: C ++ просто не має незмінного ключового слова чи мовної підтримки. А також, я припускаю, що програміст розумно використовує мову: інакше const теж не має абсолютно ніякого значення.
К.Стефф

1
@ K.Steff - можливо, краще сказати, що немає додаткової незмінності у C ++, окрім передбачених const
Мартін Беккет

Абсолютно точний :)
К.Стефф

У C ++ вони зовсім не однакові. const - це рівень доступу лише для читання, це не означає, що дані незмінні. Ви можете обійти його на C ++, більшу частину часу.
Клаїм

0

У C, C ++ і суміжних мовах також існує різниця між об'єктом const і вашим посиланням або вказівником на об'єкт, який є постійною посиланням.

Якщо ви намагаєтеся змінити постійний об'єкт, ви отримуєте не визначену поведінку. (Ви можете спробувати змінити константний об'єкт, наприклад, взявши його адресу, накинувши адресу на неконст-покажчик, а потім використовуючи цей покажчик non-const для зміни об’єкта).

Постійний вказівник або посилання з іншого боку просто повідомляє компілятору, що ви не можете використовувати цей покажчик чи посилання для зміни об'єкта. Ви можете кинути вказівник або посилання і спробувати змінити об'єкт. Якщо сам об’єкт був постійним, трапляться погані речі. Якщо об’єкт насправді не був постійним, він зміниться. Це, звичайно, може заплутати користувачів вашого коду і, можливо, призвести до помилок.

У C, якщо ви використовуєте рядковий літерал на зразок "Привіт", п'ять знаків і кінцевий нульовий байт насправді є постійними, але ви отримуєте не-const вказівник. Дуже погана ідея використовувати цей неконст-покажчик для зміни об'єкта.

У C ви можете мати вказівник "const restrict". Це означає, що об’єкт, на який вказували, є тимчасово постійним. Якщо об'єкт модифікований будь-якими способами, поки покажчик "const restrict" знаходиться в області дії, ви отримуєте не визначену поведінку. Це сильніше, ніж вказівник const, який лише заважає вам змінювати об'єкт через цей покажчик.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.