Поймать это? Константа была добавлена одновременно с локальной переменной.
Нет, он не был добавлен и не являлся локальной переменной.
Объект single , к которому оба относятся константа и локальная переменная, был добавлен, но ни константа, ни локальная переменная не были изменены. Вы не можете изменять или изменять переменную или константу в Ruby (по крайней мере, не так, как подразумевает ваш вопрос), единственное, что вы можете изменить - это объекты.
Единственные две вещи, которые вы можете делать с переменными или константами, - это разыменовывать их и присваивать им.
Константа здесь - красная сельдь, она совершенно не имеет отношения к приведенному примеру. Единственное, что имеет отношение к делу, это то, что во всем примере только один один объект. Этот единственный объект доступен под двумя разными именами. Если объект изменяется, то объект изменяется. Период. Это не таинственно разделить себя на две части. Какое имя вы используете, чтобы посмотреть на измененный объект, не имеет значения. В любом случае, есть только один объект.
Это работает точно так же, как и в любом другом языке программирования: если у вас есть несколько ссылок на изменяемый объект, скажем, в Python, Java, C #, C ++, C, Lisp, Smalltalk, JavaScript, PHP, Perl или любой другой, тогда любое изменение в этом объекте будет видимым независимо от того, какая ссылка используется, даже если некоторые из этих ссылок final
или const
или как этот конкретный язык называет их.
Это просто то, как работает общее изменяемое состояние, и это лишь одна из многих причин, по которым общее изменяемое состояние является плохим.
В Ruby обычно можно вызывать метод freeze
для любого объекта, чтобы сделать его неизменным. Однако, опять же, вы модифицируете объект здесь, так что любой, кто имеет ссылку на этот объект, внезапно обнаружит, что объект стал неизменным. Поэтому, чтобы быть в безопасности, сначала нужно скопировать объект, вызвав dup
. Но, конечно, этого тоже недостаточно, если вы думаете о массиве, например: если вы dup
массив, вы получите другой массив , но объекты внутри массив все те же, что и в исходном массиве. И если вы freeze
массив, то вы больше не можете изменять массив , но объекты в массив вполне могут быть изменяемыми:
ORIG = ['Hello']
CLONE = ORIG.dup.freeze
CLONE[0] << ', World!'
CLONE # => ['Hello, World!']
Это общее изменяемое состояние для вас. Единственный способ избежать этого безумия - это либо отказаться от общего состояния (например, программирование актера: если никто больше не может его видеть, то не имеет значения, как часто или когда оно меняется), либо изменчивого состояния (например, функциональное программирование: если оно никогда не происходит). меняется, тогда не имеет значения, сколько это видят другие).
Тот факт, что одна из двух переменных в исходном примере на самом деле является константой, совершенно не имеет отношения к проблеме. Существует два основных различия между переменной и константой в Ruby: у них разные правила поиска, и константы генерируют предупреждение, если они назначены более одного раза. Но в этом примере правила поиска не имеют значения, и константа назначается только один раз, поэтому в данном случае действительно нет разницы между переменной и константой.