Как получить доступ к свойству экземпляра класса, переданного конструктору другого класса

#ruby #constructor

Вопрос:

выходец из мира .net и делаю свои первые шаги в Ruby. Это должно быть довольно просто, но все же мне чего-то не хватает:

 class TestClass   def initialize(foo_class)  puts foo_class.number  end end   class FooClass  @number = 3   attr_accessor :number end  foo_class = FooClass.new test_class = TestClass.new(foo_class)  

Я ожидал бы, что число 3 появится в выводе, но вместо этого оно равно нулю. Но я определил @number всего одним@, чтобы убедиться, что это переменная экземпляра, поэтому она должна быть присоединена к экземпляру, который я передаю конструктору TestClass. Что я упускаю?

Ответ №1:

Переменные экземпляра принадлежат экземплярам. Вот почему они называются переменными экземпляра. Здесь у вас есть две переменные экземпляра, обе из которых вызываются @number и принадлежат двум разным экземплярам.

Один из них принадлежит FooClass другому . Этот инициализируется для 3 . Еще один принадлежит foo_class мне . Этот параметр никогда не присваивается, следовательно, он неинициализирован и, следовательно, оценивается nil как .

Если вы хотите, чтобы он имел определенное значение, вам действительно нужно его назначить: вы определили метод записи атрибутов, но никогда не вызываете его:

 foo_class.number = 4  

Теперь переменная @number экземпляра foo_class инициализируется на 4 .

Если вы не хотите, чтобы ваши пользователи не забывали инициализировать переменную экземпляра самостоятельно, вы можете использовать метод инициализатора. Обратите внимание, что методы инициализатора не являются чем-то особенным, они являются методами, как и любой другой метод.

Однако большинство объектов создаются путем вызова метода Class#new factory, который выглядит примерно так:

 class Class  def new(...)  obj = allocate  obj.initialize(...)  obj  end end  

Как вы можете видеть, реализация по умолчанию Class#new вызывает метод экземпляра, вызываемый initialize для вновь созданного экземпляра, что означает, что вы можете настроить инициализацию, переопределив #initialize :

 class FooClass  @number = 3   attr_accessor :number   def initialize  self.number = 4  end end  

Теперь гарантируется, что переменная @number экземпляра любого экземпляра FooClass всегда будет инициализирована на 4 (по крайней мере, когда пользователи используют Class#new заводской метод по умолчанию).

Комментарии:

1. Это не могло быть яснее, чем это! Большое спасибо!

2. Правило № 1 понимания Ruby: подумайте о том, что представляет собой объект в этом месте кода. Правило № 1.a понимания Ruby, когда вы исходите из таких языков, как Java, C или C#: не забывайте, что, когда мы говорим «Все является объектом», мы имеем в виду это. Модули и классы также являются объектами. Итак, у вас была правильная переменная экземпляра, но неправильный объект.