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 

我如何在ruby中做同样的事情?

为了对比@ 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" 

上面提到的@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 

这是我最终找到使用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 – 无需覆盖初始化。

这也是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是实例变量。

有一个问题:你可以覆盖@var:
Salmon.var =’shark’将覆盖@var,所以
puts(Salmon.new).v#=>鲨鱼