Class-level instance variables

от автора

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

class User   @var = 1 end 

Ожидаемое поведение

Переменные экземпляра работают так, как от них ожидают в обычных ситуациях:

class A   def set_a( v );  @a = v;  end   def get_a; return @a; end end  o1 = A.new o1.instance_variables   # => [] o1.get_a   # => nil  o1.set_a 123 o1.instance_variables   # => ["@a"] o1.get_a   # => 123  o2 = A.new o2.get_a   # => nil 

Переменная появляется в экземпляре после ее установки, дальше все работает как по маслу — она видна только в своем экземпляре.

Значение по-умолчанию

Неожиданности с переменныой экземпляра обычно начинаются когда нужно установить значение ее по-умолчанию:

class B   attr_accessor :b       # вместо set_b, get_b из вышестоящего примера   @b = 1 end  o1 = B.new o1.b    # => nil o1.instance_variables   # => []  o1.b = 2 o1.b    # => 2 o1.instance_variables   # => ["@b"] 

Оп-па. А где же наше значение по-умолчанию? Почему переменной вообще нет в обьекте с самого начала?

Такие переменные называются Class-Level Instance Variable (как это по-русски «переменные экземпляра Class-уровня»?)

Классы это объекты.

На Ruby, что любой код выполняется в контексте текущего обьекта (экземпляра класса), текущий объект всегда доступен из псевдо-переменной self. Это базовые истинины. Но попорбуйте ответить на вопрос, в каком конексте (объекте) выполняется строка 4 и строка 2?

1: class User 2:   @b = 1 3:   def a 4:     @a = 1 5:   end 6: end 

Строка 4 выполнится в экземпляре класса User, как мы и ожидаем, в объекте который вы создадите через User.new

А строка 2 выполняется в экземпляре класса Class, в объекте который описывает класс User. Этот объект создатся сразу после чтения интерпретатором класса User.
Само слово User это не что иное как консанта, значение которой объект типа Class. Этот объект описывает наш класс User. Именно к этому объекту относится переменная @b.

o1 = B.new o1.b    # => nil o1.instance_variables   # => []  B.instance_variables    # => ["@b"] 

На самом деле она всегда была там. Не в классе B и не в экземпляре класса B, а в экземпляре класса Class хранимом в константе B.

Применение

Что нам дают переменные экземпляра Class-уровня?

Они могут работать как личные переменные класса. В отличии от настоящих переменных класса, которые доступных во всех потомках и экземплярах под одним именем, наша переменная принадлежит только тому классу в контексте которого была объявлена.

class B   @b = 1   def self.set_b( v ); @b = v;  end   def self.get_b; @b; end end  B.get_b   # => 1  B.set_b 2 B.get_b   # => 2  class B1 < B; end  B1.get_b  # => 1 B1.set_b 3 B1.get_b   # => 3  B.get_b    # => 2 

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

class C   @@c = 1   def self.set_c( v ); @@c = v;  end   def self.get_c; @@c; end end  C.get_c   # => 1  C.set_b 2 C.get_b   # => 2  class C1 < C; end C1.get_c  # => 2  C1.set_c 3 C1.get_c   # => 3 C.get_c    # => 3  class C2 < C; @@c = 4; end C.get_c   # => 4 C1.get_c   # => 4 C2.get_c   # => 4 

Accessors

Такие переменные с помощью акцессоров создаются следующим образом:

class A   class << self     attr_accessor :a   end   # Вместо этого такая строка: self.class.attr_accessor :a   # невозможна только потому, что attr_accessor это private method :( end  A.instance_variables # => ["@a"] A.class_variables    # => [] A.a   # => nil  A.a = 123 A.a   # => 123 

Обратите внимание что рельсовый cattr_accessor :a создаст методы с такими же именами, только обращаться они будут к переменной класса.

class User   cattr_accessor :a end  User.instance_variables  # => [] User.class_variables     # => ["@@a"] 

Материалы по теме:

railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/
wiseheartdesign.com/articles/2006/09/22/class-level-instance-variables/
snippets.dzone.com/posts/show/4382

Уважаемые читатели, если не трудно, накидайте сюда еще ссылок по теме, чтобы можно было использовать этот материал как учебный по теме.

ссылка на оригинал статьи http://habrahabr.ru/post/111781/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *