Що означає незмінне?


103

Якщо рядок є незмінним, чи означає це, що .... (припустимо, JavaScript)

var str = 'foo';

alert(str.substr(1)); // oo

alert(str); // foo

Це означає, що при виклику методів у рядку він поверне модифіковану рядок, але вона не змінить початкову рядок?

Якщо рядок був змінним, чи означає це, що 2- alert()й повернеться ooтакож?

Відповіді:


104

Це означає, що щойно інстанціюючи об'єкт, ви не зможете змінити його властивості. У першому попередженні ви не змінюєте foo. Ви створюєте новий рядок. Ось чому у вашому другому сповіщенні він відображатиметься "foo" замість oo.

Це означає, що при виклику методів у рядку він поверне модифіковану рядок, але вона не змінить початкову рядок?

Так. Ніщо не може змінити рядок після її створення. Тепер це не означає, що ви не можете призначити новий струнний об'єкт strзмінній. Ви просто не можете змінити поточний об'єкт, на який посилається str.

Якщо рядок було вимкнено, чи означає це, що 2-е попередження () також повернеться oo?

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


Цей самий рядок, якщо його змінити і призначити, оновить рядок var str = 'foo'; str = str.substr (1)); // oo попередження (str); // oo
Ashwin G

Що про код нижче. Значення рядка зараз змінено. var name = "Сантош"; console.log (name.substr (0,2)); var name = "kumar" console.log (ім'я); Як все ще непорушно
Сантош

97

На нижчому рівні незмінність означає, що пам'ять, в якій зберігається рядок, не буде змінена. Після створення рядка "foo"виділяється деяка пам’ять для зберігання значення "foo". Ця пам'ять не буде змінена. Якщо ви змінюєте рядок, скажімо, substr(1)створюється нова рядок і виділяється інша частина пам'яті, яка буде зберігатися "oo". Тепер у вас є два рядки в пам'яті "foo"та "oo". Навіть якщо ви більше не збираєтесь користуватися "foo", він буде триматися, поки не збирається сміття.

Одна з причин, чому струнні операції є порівняно дорогими.


1
Числа теж незмінні.
Р. Н. Кушваха

3
привіт від 2015 року !! "На нижчому рівні незмінність означає, що пам'ять, в якій зберігається рядок, не буде змінена." --- це занадто обмежувально і не звучить правильно. Незмінність стосується лише користувачів, віртуальна пам'ять може бути змінена, як алокатор пам'яті подобається, як тільки зберігаються інваріанти мовних специфікацій.
zerkms

2
Ця відповідь є більш логічною, ніж відповідь, що сприймається.
Еджаз Карим

Але я можу зробити, як var str = 'foo'; я можу змінити через str = 'bar'. значення значення змінилося таким чином, правда?
Хакер

@Hacker Nope. Ви призначили нову рядок змінної, яка вказує на нове місце в пам'яті.
деге

13

Невідмінна означає те, що неможливо змінити чи змінити.

Отже, коли ви присвоюєте значення рядку, це значення створюється з нуля, а не замінюється. Тому щоразу, коли новому значенню присвоюється один і той же рядок, створюється копія. Тож насправді ви ніколи не змінюєте початкове значення.


9

Я не впевнений у JavaScript, але в Java, рядки роблять додатковий крок до незмінності за допомогою "String Constant Pool". Рядки можуть бути побудовані за допомогою рядкових літералів ( "foo") або з Stringконструктором класу. Рядки, побудовані за допомогою рядкових літералів, є частиною String Constant Pool, і той самий рядковий літерал завжди буде однаковою адресою пам'яті з пулу.

Приклад:

    String lit1 = "foo";
    String lit2 = "foo";
    String cons = new String("foo");

    System.out.println(lit1 == lit2);      // true
    System.out.println(lit1 == cons);      // false

    System.out.println(lit1.equals(cons)); // true

У вищесказаному обидва lit1і lit2будуються за допомогою одного і того ж літерального рядка, тому вони вказують на одну і ту ж адресу пам'яті;lit1 == lit2призводить до того true, що вони є абсолютно одним і тим же об'єктом.

Однак consпобудований за допомогою конструктора класів. Хоча параметр є однаковою строковою константою, конструктор виділяє нову пам'ять для cons, тобто consне є тим самим об'єктом, що lit1іlit2 , незважаючи на те, що містить ті самі дані.

Звичайно, оскільки всі три рядки містять однакові символьні дані, використовуючи equals методу повернеться true.

(Звичайно, обидва типи струнних конструкцій незмінні)


3

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

Використання StringBuffer під час маніпулювання Strings натомість робить операцію більш ефективною, оскільки StringBuffer зберігає рядок у масиві символів зі змінними, щоб утримувати ємність символьного масиву та довжину масиву (String у формі масиву char)


3

Визначення змінних підручників підручника може піддаватися зміні або зміні. У програмуванні ми використовуємо слово для позначення об’єктів, стан яких дозволено змінюватись з часом. Незмінне значення - якраз протилежне - після його створення воно ніколи не може змінитися.

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

var statement = "I am an immutable value";
var otherStr = statement.slice(8, 17);

Думаю, ніхто не здивується, дізнавшись, що другий рядок жодним чином не змінює рядок у операторі. Насправді жоден рядовий метод не змінює рядок, над яким вони працюють, всі вони повертають нові рядки. Причина полягає в тому, що струни незмінні - вони не можуть змінюватися, ми можемо коли-небудь робити нові рядки.

Рядки - не єдині незмінні значення, вбудовані в JavaScript. Числа теж незмінні. Чи можете ви навіть уявити собі середовище, коли оцінюючи вираз 2 + 3, змінюється значення числа 2? Це звучить абсурдно, але ми все це робимо зі своїми об’єктами та масивами.


2

Від рядків до стеків ... простий для розуміння приклад, взятий з блогу Еріка Ліпперта :

Пошук шляху за допомогою A * в C # 3.0, частина друга ...

Змінений стек на зразок System.Collections.Generic.Stack явно не підходить. Ми хочемо мати можливість пройти існуючий шлях і створити з нього нові шляхи для всіх сусідів його останнього елемента, але натискання нового вузла на стандартний стек змінює стек. Нам потрібно було б зробити копії стека, перш ніж натискати на нього, що нерозумно, оскільки тоді ми б дублювали весь його вміст без потреби.

Іммунізовані стеки не мають цієї проблеми. Натискання на незмінний стек просто створює абсолютно новий стек, який посилається на старий як його хвіст. Оскільки стек є незмінним, немає небезпеки, що якийсь інший код зійде і зіпсується з вмістом хвоста. Ви можете продовжувати використовувати старий стек до змісту вашого серця.

Щоб заглибитись у розуміння незмінності, прочитайте публікації Еріка, починаючи з цього:

Незмінюваність у першій частині C #: види непорушності


Ця цитата містить дивну претензію - структура даних про стеки (насправді декілька стеків із спільним поділом хвоста) - це в цілому структура, що змінюється - кожен натиск чи попп змінюють структуру. Тільки окремі предмети незмінні. І в принципі ви могли мати ту саму структуру, але зі змінними елементами. Це трапляється в деяких варіантах неприпустимого з'єднання IIRC. Незмінність має великі переваги, але обмін частиною або всією структурою даних як оптимізація цілком можливий із мутабелями. Навіть якщо ви хочете очевидну незмінність для інших посилань, ви завжди можете скопіювати напис за потребою
Steve314

0

Один із способів зрозуміти цю концепцію - це переглянути, як JavaScript обробляє всі об'єкти, що є посиланням. Це означає, що всі об'єкти можуть бути змінені після інстанції, це означає, що ви можете додати об'єкт за допомогою нових методів та властивостей. Це має значення тому, що якщо ви хочете, щоб об'єкт був незмінним, об'єкт не може змінитися після інстанції.

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