Подтвердить что ты не робот

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

Класс-экземпляр класса ruby ​​дает мне головную боль. Я понимаю, учитывая это...

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

Как мне сделать то же самое в рубине?

4b9b3361

Ответ 1

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

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"

Ответ 2

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

В любом случае это эквивалентный код 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

Ответ 3

В этой версии я выяснил, используя ссылку 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 - не нужно переопределять инициализацию.

Ответ 4

Это распространенная ошибка, с которой 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 внутри определения метода - это переменная экземпляра.

Ответ 5

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