В Ruby все переменные являются указателями на объекты, то есть массивы, хэши, строки, целые числа.

Взгляните на этот пример из одного из упражнений Launch School:

name = ‘Bob’ 
save_name = name 
name = ‘Alice’ 
puts name, save_name

Посмотрите сначала на первые 2 строки. В первой строке инициализируется новая переменная (имя) для ссылки на строковый объект «Боб».

В следующей строке save_name указывает на имя переменной. Но помните: все переменные являются указателями на объекты. Следовательно, save_name также указывает на объект. Вопрос какой объект?

save_name указывает на какое имя. На что указывает имя? Строковый объект «Боб». Итак, save_name также указывает на «Боба».

name и save_name указывают на один и тот же объект.

Глядя теперь на третью строку, имя теперь переназначается на «Алиса». name теперь указывает на другое место в памяти. Обратите внимание, что исходная переменная имени все еще существует, только с другим идентификатором объекта. Кроме того, на исходный объект, который был переназначен, теперь нельзя ссылаться по «имени».

Итак, следующий вопрос: на какой объект теперь указывает save_name? Мы знаем, что имя было переназначено. Но относится ли save_name ко второму или первому объекту? Итак, мы только что сказали, что исходная переменная name все еще существует и не была изменена. Поэтому save_name указывает на исходную переменную имени «Боб».

Таким образом, имя возвращает «Алиса». И ставит save_name возвращает «Боб».

Теперь взгляните на это, еще одно из упражнений Launch School:

name = ‘Bob’ 
save_name = name 
name.upcase! 
puts name, save_name

Во второй строке выполняется деструктивный вызов метода для имени переменной. Мы знаем, что деструктивные вызовы методов мутируют или постоянно изменяют вызывающую программу, то есть исходную переменную. Так что в этом случае вызов upcase! постоянно изменяет имя. Так что теперь имя «БОБ». Так что save_name тоже «BOB».

Следовательно

puts name, save_name 

возвращается

“BOB”
“BOB”

Теперь возьмем этот пример.

array1 = %w(Moe Larry Curly Chemp Harpo Chico Groucho Zeppo) 
array2 = [] 
array1.each { |value| array2 << value } 
array1.each { |value| value.upcase! if value.start_with?(‘C’) } 
puts array2

Здесь array1 указывает на массив строк. array2 указывает на пустой массив.

В третьей строке мы перебираем каждый элемент массива1 и выполняем деструктивный вызов метода для массива2 с каждой итерацией. В частности, мы добавляем каждый элемент массива1 в массив2.

А вот и сложная часть.

В четвертой строке мы снова перебираем каждый элемент массива1 и выполняем деструктивный вызов метода для каждого элемента массива1. В частности, мы постоянно прописываем каждое слово, начинающееся с буквы C.

Вопрос в том, что делает вывод array2? Чтобы свести к минимуму путаницу, давайте сначала обновим array1 и array2.

array1 = %w(Moe Larry Curly Chemp Harpo Chico Groucho Zeppo) 
array2 = %w(Moe Larry Curly Chemp Harpo Chico Groucho Zeppo)

Просто смотреть на вышесказанное обманчиво. Потому что вы могли бы подумать, что массив2, хотя и имеет то же содержимое, что и массив1, отделен от массива1, так что если вы измените массив1, это изменение не повлияет на массив2. Но ответ не так прост.

array2 на самом деле содержит те же строковые объекты, что и array1, т. е. они ссылаются или указывают на одни и те же строковые объекты. Это не новые копии этих строковых объектов. На самом деле это новые ссылки на исходные строковые объекты. Это объясняет, почему все, что происходит с исходными строковыми объектами, теперь повлияет на новые ссылки.