Я немного смущен объектным присвоением и указателями в Ruby, и кодирован этот отрывок для тестирования моих предположений.
class Foo
attr_accessor :one, :two
def initialize(one, two)
@one = one
@two = two
end
end
bar = Foo.new(1, 2)
beans = bar
puts bar
puts beans
beans.one = 2
puts bar
puts beans
puts beans.one
puts bar.one
Я предположил, что, когда я присвоил панель бобам, она создаст копию объекта, и изменение того не влияло бы на другой. Увы, вывод показывает иначе.
^_^[jergason:~]$ ruby test.rb
#<Foo:0x100155c60>
#<Foo:0x100155c60>
#<Foo:0x100155c60>
#<Foo:0x100155c60>
2
2
Я полагаю, что числа имеют некоторое отношение к адресу объекта, и они - то же для обоих бобов и панели, и когда я изменяю бобы, панель изменяется также, который не является тем, что я ожидал. Кажется, что я только создаю указатель на объект, не копию его. Что я должен сделать для копирования объекта на присвоении, вместо того, чтобы создать указатель?
Тесты с классом Массива показывают некоторое странное поведение также.
foo = [0, 1, 2, 3, 4, 5]
baz = foo
puts "foo is #{foo}"
puts "baz is #{baz}"
foo.pop
puts "foo is #{foo}"
puts "baz is #{baz}"
foo += ["a hill of beans is a wonderful thing"]
puts "foo is #{foo}"
puts "baz is #{baz}"
Это производит следующий вывод wonky:
foo is 012345
baz is 012345
foo is 01234
baz is 01234
foo is 01234a hill of beans is a wonderful thing
baz is 01234
Это уносит мой ум. Вызов поп на нечто влияет на baz также, таким образом, это не копия, но конкатенация чего-то на нечто только влияет на нечто, и не baz. Таким образом, когда я имею дело с исходным объектом, и когда я имею дело с копией? В моих собственных классах, как я могу удостовериться, что присвоение копирует, и не делает указатели? Выручите этого смущенного парня.
В этом вопросе много вопросов. Главное, что нужно знать: присваивание никогда не создает копию в ruby, но методы часто возвращают новые объекты вместо изменения существующих объектов . Для неизменяемых объектов, таких как Fixnums, вы можете игнорировать это, но для таких объектов, как массивы или экземпляры Foo, чтобы сделать копию, вы должны сделать bar.dup
.
Что касается примера массива, foo + =
не объединяется с массивом, хранящимся в foo
, для этого вы должны сделать foo.concat (['a '])
. Вместо этого он создает новый массив и присваивает ему foo
. В документации для класса Array упоминается, какие методы изменяют массив на месте, а какие возвращают новый массив.
+
и -
в Array
каждый возвращает new массивы, заполненные соответствующим содержимым, поэтому foo += [...]
не влияет на baz
- это нормально. Попробуйте использовать оператор <<
на foo
, и в результате baz
получит такое же изменение.
Я не уверен, как Ruby обрабатывает другую вещь внутри, но вы можете попробовать использовать one.clone
и two.clone
в Foo#initialize
.