Странная особенность? Ruby Arrays - PullRequest
0 голосов
/ 14 декабря 2010

Я наткнулся на эту странную особенность (?) Массивов в Ruby, и было бы очень полезно, если бы кто-то мог объяснить мне, почему они работают так, как они.

Сначала давайте приведем пример того, как все обычно работает.

a = "Hello" #=> "Hello"
b = a #=> "Hello"
b += " Goodbye" #=> "Hello Goodbye"
b #=> "Hello Goodbye"
a #=> "Hello"

Хорошо, круто, когда вы используете =, он создает копию объекта (на этот раз строку).

Но когда вы используете массивы, это происходит:

a = [1,2,3] #=> [1,2,3]
b = a #=> [1,2,3]
b[1] = 5 #=> [1,5,3]
b #=> [1,5,3]
a #=> [1,5,3]

Теперь это просто странно. Это единственный обнаруженный мной объект, который не копируется при использовании =, а просто создает ссылку на исходный объект.

Может ли кто-то также объяснить (должен быть метод) для копирования массива, не указывая его на исходный объект?

Ответы [ 3 ]

11 голосов
/ 14 декабря 2010

На самом деле, вы должны пересмотреть свою предпосылку.

Строковое присвоение действительно b = b + " Goodbye". Операция b + " Goodbye" возвращает совершенно новую строку, поэтому переменная b указывает на новый объект после присваивания.

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

Если вы ищете обоснование для мутирующего и функционального поведения массивов, это просто. Ничего не получится, изменив строку. Скорее всего, в любом случае необходимо выделять новую память, поэтому создается совершенно новая строка.

Но массив может быть сколь угодно большим. Создание нового массива для изменения только одного элемента может быть очень дорогим. И в любом случае массив похож на любой другой составной объект. Изменение отдельного атрибута не обязательно влияет на любые другие атрибуты.

А чтобы ответить на ваш вопрос, вы всегда можете сделать:

b = a.dup
1 голос
/ 14 декабря 2010

Попробуйте ваш массив с строкой:

a = "Hello" #=> "Hello"
b = a #=> "Hello"
b[1] = "x" #=> "x"
b #=> "Hxllo"
a #=> "Hxllo"

В этом отношении строки и массивы работают одинаково.

Ключевое различие в двух случаях, как вы их написали, заключается в следующем:

b += " Goodbye"

Это синтаксическая стенография для

b = b + " Goodbye"

, который создает новую строку из b + " Goodbye", а затем присваивает ее b. Способ изменения существующей строки вместо создания новой -

b << " Goodbye"

И если вы включите это в свою последовательность, вы увидите, что она изменяет и a, и b, поскольку обе переменные ссылаются на один и тот же строковый объект.

Что касается глубокого копирования, здесь есть приличная часть:

http://ruby.about.com/od/advancedruby/a/deepcopy.htm

1 голос
/ 14 декабря 2010

Что происходит, так это то, что ruby ​​обрабатывает объект Array по ссылке, а не по значению.

Таким образом, вы можете видеть это так:

 b= [1,2,3]
 a= b

              --'b' Points to---> [1,2,3] <--'a' points t---

Так что вы можете видеть обауказывать на ту же ссылку, это означает, что если вы измените что-либо в a, это будет отражено на b.

Что касается вашего вопроса о копировании объекта, вы можете использовать метод Object # clone для этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...