Назначение объектов и указатели

Я немного запутался в назначении объектов и указателях в 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

Я предполагал, что когда я назначу bar бобам, он создаст копию объекта, и изменение одного не повлияет на другой. Увы, вывод показывает обратное.

^_^[jergason:~]$ ruby test.rb 
#<Foo:0x100155c60>
#<Foo:0x100155c60>
#<Foo:0x100155c60>
#<Foo:0x100155c60>
2
2

Я считаю, что числа как-то связаны с адресом объекта, и они одинаковы как для bean-компонентов, так и для bar, и когда я изменяю bean-компоненты, bar также меняется, чего я не ожидал. Похоже, я создаю только указатель на объект, а не его копию. Что мне нужно сделать, чтобы скопировать объект при назначении вместо создания указателя?

Тесты с классом Array также показывают странное поведение.

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}"

Это приводит к следующему шаткому выводу:

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

Это сводит меня с ума. Вызов pop для foo также влияет на baz, поэтому это не копия, но объединение чего-либо с foo влияет только на foo, а не на baz. Итак, когда я имею дело с исходным объектом, а когда — с копией? В моих собственных классах, как я могу убедиться, что присваивание копируется, а не создает указатели? Помогите этому запутавшемуся парню.


person jergason    schedule 14.04.2010    source источник


Ответы (4)


В этом вопросе много вопросов. Главное, что нужно знать, это то, что присваивание никогда не создает копии в ruby, но методы часто возвращают новые объекты вместо изменения существующих. Для неизменяемых объектов, таких как Fixnum, вы можете игнорировать это, но для таких объектов, как массивы или экземпляры Foo, чтобы сделать копию, вы должны выполнить bar.dup.

Что касается примера с массивом, foo += не объединяется с массивом, хранящимся в foo, для этого вы должны сделать foo.concat(['a']). Вместо этого он создает новый массив и присваивает ему foo. В документации к классу Array упоминается, какие методы изменяют массив на месте, а какие возвращают новый массив.

person mckeed    schedule 14.04.2010
comment
Как бы я реализовал функциональность .clone в своих собственных классах? - person jergason; 14.04.2010
comment
Реализация clone в Foo просто вернет Foo.new(self.one, self.two) - person mckeed; 14.04.2010
comment
В этом случае унаследованный Object#clone также будет работать, потому что он также копирует переменные экземпляра. - person Mladen Jablanović; 14.04.2010
comment
Object#dup если вы хотите, чтобы ваш объект не был заморожен - person Joern Akkermann; 24.05.2011

+ и - в Array каждый возвращает новые массивы, заполненные соответствующим содержимым, поэтому foo += [...] не влияет на baz — это нормально. Попробуйте применить оператор << к foo, и результат будет baz с тем же изменением.

Я не уверен, как Ruby обрабатывает другие вещи внутри, но вы можете попробовать использовать one.clone и two.clone в Foo#initialize.

person hermannloose    schedule 14.04.2010

Вы никогда не имеете дело с копией. Это тот же объект в памяти, но вы просто объявляете 2 ссылки на него: в вашем первом примере: bar и beans указывают на один и тот же объект в памяти; и во втором примере: foo и baz изначально указывают на один и тот же массив в памяти.

Посмотрите на 2 изображения/рисунка на странице руководства по Java, которые объясняют механизм (он такой же, как в Ruby), и только на эти 2 изображения, которые стоят больше, чем любое объяснение словами: http://docs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html

person Luisa    schedule 08.11.2012

По сути, ruby ​​​​использует ссылочный указатель, поэтому, когда вы меняете что-то одно, это также влияет на другое.

person SSP    schedule 13.02.2012