Почему отсутствие оператора присваивания позволяет мне изменять константу Ruby без предупреждения компилятора? - PullRequest
4 голосов
/ 22 марта 2009

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

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

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

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

Ответы [ 4 ]

7 голосов
/ 22 марта 2009

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

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

6 голосов
/ 22 марта 2009

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

4 голосов
/ 22 марта 2009

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

X = "foo".freeze        # => "foo" 
X.concat("bar")

TypeError: can't modify frozen string
    from (irb):2:in `concat'
    from (irb):2

Я настоятельно рекомендую вам прочитать Язык программирования Ruby .

0 голосов
/ 22 марта 2009

Это потому, что константа X хранит ссылку на объект String. В первом примере вы изменяете внутреннее состояние объекта String, но не ссылку, сохраненную константой. Во втором примере вы меняете ссылку, сохраненную константой, на новый объект String, возвращаемый методом concat.

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

...