Почему отсутствие оператора присваивания позволяет мне изменять константу Ruby без предупреждения компилятора?
-
21-08-2019 - |
Вопрос
В следующих двух примерах я делаю то же самое, создавая постоянную строку и используя метод concat для ее изменения.Поскольку это константа, я ожидаю предупреждения компилятора, но получаю его только во втором примере, когда я использую оператор присваивания.Почему это происходит?
X = "hello"
X.concat(" world")
puts X # no warning
X = "hello"
X = X.concat(" world")
puts X # warning: already initialized
Поскольку метод concat изменяет строку на месте, это обычно то, что я бы сделал, поскольку нет необходимости использовать оператор присваивания.Итак, почему наличие оператора присваивания заставляет компилятор идентифицировать эти две операции как разные?
Решение
Это потому, что вы переопределяете новый X.Когда вы переопределяете константу, это выдает вам ошибку "уже инициализировано".Первый пример не выдает этой ошибки, потому что вы не переопределяете X, вы изменяете его.
Другие советы
В Ruby переменные по сути являются указателями на место в памяти, содержащее объект, а не на сам объект.Во втором примере вы инициализируете константу X
указывать на объект в первой строке (X = "hello"
), и во второй строке вы снова инициализируете константу, но она уже указывает на объект, поэтому вы получаете ошибку.
Неизменяемость константы не означает, что вы не можете изменить объект - это просто означает, что вы не можете изменить константу так, чтобы она указывала на другой объект.
Если вы хотите сделать свою строку "реальной" константой, попробуйте "заморозить":
X = "foo".freeze # => "foo"
X.concat("bar")
TypeError: can't modify frozen string
from (irb):2:in `concat'
from (irb):2
Я действительно призываю вас читать Язык программирования Ruby.
Это происходит потому, что постоянная X
хранит ли ссылка на String
объект.В вашем первом примере вы изменяете внутреннее состояние String
объект, но не ссылка, хранящаяся в константе.Во втором примере вы меняете ссылку, сохраненную константой, на новую String
объект, который возвращается из concat
способ.
Книга о кирке объясняет это здесь.