Переменные класса Ruby - PullRequest
       31

Переменные класса Ruby

22 голосов
/ 18 января 2010

Рубиновый экземпляр вызывает у меня головную боль. Я понимаю, учитывая это ...

class Foo
  @var = 'bar'
end

... что @var является переменной в экземпляре созданного класса.

Но как мне создать переопределенную переменную класса подкласса?

Вот пример того, что я бы сделал в Python:

class Fish:
var = 'fish'
def v(self):
    return self.var

class Trout(Fish):
    var = 'trout'

class Salmon(Fish):
    var = 'salmon'

print Trout().v()
print Salmon().v()

Какие выходы:

trout
salmon

Как мне сделать то же самое в ruby?

Ответы [ 5 ]

21 голосов
/ 18 января 2010

Чтобы сопоставить ответ @ khelll, здесь используются переменные экземпляра для объектов Class:

class Fish
  # an instance variable of this Class object
  @var = 'fish'

  # the "getter"
  def self.v
    @var
  end

  # the "setter"
  def self.v=(a_fish)
    @var = a_fish
  end
end

class Trout < Fish
  self.v = 'trout'
end

class Salmon < Fish
  self.v = 'salmon'
end

p Trout.v   # => "trout"
p Salmon.v  # => "salmon"

Редактировать: , чтобы предоставить экземплярам доступ на чтение к переменной экземпляра класса:

class Fish
  def type_of_fish
    self.class.v
  end
end

p Trout.new.type_of_fish   # => "trout"
p Salmon.new.type_of_fish  # => "salmon"
8 голосов
/ 18 января 2010

@var упомянутый выше называется переменная экземпляра класса , которая отличается от переменные экземпляра ... прочитайте ответ здесь , чтобы увидеть разницу

В любом случае это эквивалентный код Ruby:

class Fish
  def initialize
    @var = 'fish'
  end

  def v
    @var
  end
end

class Trout < Fish
  def initialize
    @var = 'trout' 
  end
end

class Salmon < Fish
  def initialize
    @var = 'salmon' 
  end
end

puts Trout.new.v
puts Salmon.new.v
4 голосов
/ 18 января 2010

Вот версия, которую я выяснил, используя ссылку hobodave:

class Fish
  class << self
    attr_accessor :var
  end

  @var = 'fish'
  def v
    self.class.var
  end
end

class Trout < Fish
  @var = 'trout'
end

class Salmon < Fish
  @var = 'salmon'
end

puts (Trout.new).v   # => trout
puts (Salmon.new).v  # => salmon

Обратите внимание, что для подкласса требуется только добавление @var - нет необходимости переопределять инициализацию.

2 голосов
/ 18 января 2010

Это распространенная ошибка, допущенная Java-кодерами и Ruby, и один из больших концептуальных прыжков, которые мне пришлось осмыслить. Сначала это кажется странным, но на самом деле это один из круче аспектов Ruby - весь код исполняемый, включая определения классов.

Итак, переменные экземпляра должны быть объявлены внутри методов. Это связано с тем, как оценивается «я». «Я» - текущий объект. Интерпретатор сначала будет искать вызовы методов и ссылки на переменные в «self»: ​​

class Fish
    @var = "foo" # here 'self' == Fish, the constant which contains the class object  
    def foo
        # do foo
    end
end

fish = Fish.new
fish.foo # here 'self' == fish, an instance of Fish

В определении класса 'self' задается как определяемый объект класса, поэтому любые ссылки в определении класса будут ссылаться на этот объект класса, в данном случае Fish.

Когда метод вызывается для экземпляра Fish, однако, self устанавливается как получатель вызова, конкретный экземпляр Fish. Таким образом, вне определения метода self является объектом класса. Внутри метода self является экземпляром получателя. Вот почему @var вне определения метода больше похож на статическую переменную в Java, а @var внутри определения метода - это переменная экземпляра.

1 голос
/ 14 сентября 2012

Есть одна проблема: вы можете переопределить @var:
Salmon.var = 'shark' переопределит @var, поэтому
ставит (Salmon.new) .v # => shark

...