Переменные класса 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
Как мне сделать то же самое в рубине?
Ответы
Ответ 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 # = > акула