Рубиновые и классовые переменные в наследуемом классе - PullRequest
2 голосов
/ 03 декабря 2011
class A
  def set(v)
    @@v = v
  end
  def put
    puts @@v
  end
end

class B < A
end
class C < A
end

B.new.set 'b'
B.new.put # => b
C.new.set 'c'
C.new.put # => c
B.new.put # => c

Почему?И как я должен написать это, чтобы иметь 'b' в последнем B.new.put?

Ответы [ 3 ]

5 голосов
/ 03 декабря 2011

Вот хорошая статья на эту тему - Переменные класса и экземпляра в Ruby .

По сути, вы можете сделать следующее:

class A
  class << self
    attr_accessor :class_var
  end

  def set_class_var(value)
    self.class.class_var = value
  end

  def get_class_var
    self.class.class_var
  end
end

class B < A; end

A.class_var = 'a'
B.class_var = 'b'
puts A.class_var # => a
puts B.class_var # => b

A.new.set_class_var 'aa'
B.new.set_class_var 'bb'
puts A.new.get_class_var # => aa
puts B.new.get_class_var # => bb

Чтобы понять это, вы должны подумать о A как об экземпляре класса Class (и это так в Ruby). Но каждый объект в Ruby имеет свой собственный одноэлементный класс, который хранит специфичные для объекта вещи, такие как методы, определенные для самого объекта:

a = A.new
def a.foo
  puts 'foo'
end

В этом случае foo - это метод, определенный только для объекта a, а не для каждого экземпляра класса A. И еще один способ определить метод в одноэлементном классе объекта:

class << a # open a's singleton class
  def bar  # define method that will be available only on 'a' object
    puts 'bar'
  end
end

В первом фрагменте кода мы используем этот подход для определения средства доступа к атрибуту class_var в контексте одноэлементного класса нашего A класса (это немного сложно, поэтому вам нужно подумать об этом). В результате у самого класса есть переменная class_var, а также класс-потомок B. Разница в том, что у каждого из них есть собственная переменная class_var, которая не мешает работе.

2 голосов
/ 03 декабря 2011

Другой вариант - извлечь class_inheritable_accessor код из Rails и включить его поведение в ваши классы.См. здесь для хорошего обсуждения и смелости кода.

Возможно, вы действительно не хотите переменную класса.

0 голосов
/ 03 декабря 2011

Назначение значения переменной класса (переменная @@) устанавливает его для КАЖДОГО экземпляра класса. Он даже «устанавливает» его для случаев, которые «еще не созданы». Итак, рассмотрим это ...

B.new.set 'b' # OK, that set @@v for that particular instance of B

B.new.put # Hey, you just created *another* new instance of B!  

Как @@ v может иметь значение в этом? Значение второго объекта @@ v будет неустановленным, за исключением , поскольку @@ v является переменной класса , поэтому оно имеет то же значение для каждые экземпляр класса.

...