Какую роль играет неизменность строк в объяснении ссылок на строки для разработчиков? - PullRequest
4 голосов
/ 03 июля 2011

В той или иной форме я часто сталкиваюсь со следующим вопросом (поставленным здесь, в псевдокоде):

String myString = "Hello"
someObject.stringProperty = myString
myString = "World"

Почему someObject.stringProperty теперь не равно "World"?

Кажется, что существует путаница в отношении роли следующего утверждения в объяснении причины этого:

Строки неизменны

Что вы думаете?

Если вы считаете, что утверждение неприменимо, я бы спросил вас об этом: На языке, где строки были изменяемыми, а оператор присваивания мутировал ихфактическое значение (вместо простого изменения ссылки), ваш ответ все еще имеет смысл?

РЕДАКТИРОВАТЬ:

ОК, я чувствую необходимость уточнить некоторые вещи:

  1. Меня не смущает, как работают строки, ссылки или назначения.Я совершенно ясно по этой теме.Я не спрашиваю, как работают строки.Я спрашиваю «Какую роль играет неизменность строк в объяснении ссылок на строки для разработчиков».Мы можем пропустить атаки Ad-Hominem, которые я должен быть сбит с толку.

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

Категоризация существующих аргументов:

  1. String Immutability has nothing to do with it because the references are changing, not the values of the strings Этот ответ предполагает тот факт, о котором я спрашиваю.

  2. Assignment means assignment of references not assignment of values Опять же, это предполагает тот факт, о котором я спрашиваю.Нет никаких причин, по которым должен иметь место для строк.Это просто - это случай строк для производительности и других причин.

Ответы [ 3 ]

4 голосов
/ 03 июля 2011

Роль, которую играет утверждение в объяснении, зависит от самого объяснения. Это может быть вредно или полезно, в зависимости от остального объяснения.

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

House x = new House(Color.Green); // The has a green front door
House y = x;
x = new House(Color.Red);
Console.WriteLine(y.FrontDoorColor); // Still green!

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

Я бы тогда привел второй пример:

House x = new House(Color.Green); // The has a green front door
House y = x;
x.FrontDoorColor = Color.Red; // Repainting a front door
Console.WriteLine(y.FrontDoorColor); // Red!

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

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

(Я также должен указать, что, хотя ссылки ведут себя как реальные адреса, я не утверждаю, что они совпадают с "адресами памяти" или указателями. Они не должны быть . Я использую термин в строгой аналогии с реальным миром, и это все. Это обратная сторона примера, но я не думаю, что это приносит слишком много вреда.)

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

Чтобы узнать, будет ли мой ответ по-прежнему актуален в языке с изменяемыми строками, нам нужно знать больше о том, как ведут себя строковые литералы. Язык, который во всех отношениях совпадает с C # , отличным от изменчивости строк, будет ужасным языком, как вы могли бы написать:

// Hypothetical bad language
string x = "dog";
x.MutateTo("cat");
Console.WriteLine("dog"); // Prints cat!

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

4 голосов
/ 03 июля 2011

Это потому, что знак равенства в компьютерном программировании является скорее оператором присваивания, чем условием "математического равенства". То, что строка неизменна, не имеет к этому никакого отношения. Все дело в том, что знак равенства является оператором «присваивания», а не математическим ограничением эквивалентности.

Это означает, что A = B; и B = C; не означает, что A = C;

вместо этого означает

A был установлен для ссылки на значение B, поэтому значение B теперь является значением A. B был установлен для ссылки на значение C, поэтому значение C теперь является значением B, но значение A остается неизменным

Если строки не были неизменными

String myString = "Hello";
myString.replace(3, "p"); // replace starting at char #3 (the second 'l')
System.out.println(myString); // would print "Help"

Но поскольку строки неизменны,

String myString = "Hello";
myString.replace(3, "p"); // returns a new string "help" which is not assigned to anything
// since the newly returned string was not assigned to anything, it was garbage collected
System.out.println(myString); // would print "Hello"
3 голосов
/ 03 июля 2011

Объяснение состоит в том, что этот пример не имеет ничего общего с неизменностью.

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

Это ничем не отличается от высказывания

int a = 4;
int b = a;
a = 5; 

Или

string x = "Foo";
string y = x;
x = "Bar";

Или

Foo foo = new Foo() { Bar = 42 };
Foo otherFoo = foo;
foo = new Foo() { Bar = 17; }

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

...