Почему отсутствие оператора присваивания позволяет мне изменять константу Ruby без предупреждения компилятора?

В следующих двух примерах я делаю то же самое, создавая константу String и используя метод concat для ее изменения. Поскольку это константа, я ожидаю предупреждения компилятора, но получаю только одно во втором примере, когда использую оператор присваивания. Почему это?

X = "hello"
X.concat(" world")
puts X # no warning

X = "hello"
X = X.concat(" world")
puts X # warning: already initialized

Так как метод concat изменяет строку на месте, я обычно так и делаю, поскольку нет необходимости использовать оператор присваивания. Итак, почему присутствие оператора присваивания заставляет компилятор идентифицировать эти две операции как разные?

4 ответа

Решение

Это потому, что вы переопределяете новый X. Когда вы переопределяете константу, это дает вам "уже инициализированную" ошибку. Первый пример не дает этой ошибки, потому что вы не переопределяете X, вы модифицируете его.

В Ruby переменные по сути являются указателями на место в памяти, содержащее объект, а не сам объект. Во втором примере вы инициализируете константу X указывать на объект в первой строке (X = "hello"), а во второй строке вы снова инициализируете константу - но она уже указывает на объект, поэтому вы получаете ошибку.

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

Если вы хотите сделать вашу строку "настоящей" константой, попробуйте "freeze":

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 метод.

Книга PickAxe объясняет это здесь.

Другие вопросы по тегам