Ruby类变量

Ruby类变量,ruby,class,inheritance,class-variables,Ruby,Class,Inheritance,Class Variables,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'

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中如何做同样的事情?

@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
类鱼
def初始化
@var=‘鱼’
结束
def v
@变量
结束
结束
鳟鱼类
def初始化
@var=‘鳟鱼’
结束
结束
鲑鱼类
def初始化
@var=‘鲑鱼’
结束
结束
新鳟鱼
放鲑鱼。新的

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

这也是来到Ruby的Java程序员经常犯的一个错误,也是我不得不思考的一个重大概念跳跃。一开始看起来很奇怪,但这确实是Ruby的一个更酷的方面——所有代码都是可执行的,包括类定义

因此,实例变量必须在方法内部声明。这与如何评价“自我”有关“self”是当前对象。解释器将首先在“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则是实例变量

以下是我使用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
类鱼
班鳟鱼
放(鲑鱼.新的).v#=>鲑鱼

请注意,子类化只需要添加一个
@var
——无需重写initialize。

有一个问题:您可以重写@var:
Salmon.var='shark'将覆盖@var,因此

puts(Salmon.new).v#=>shark

这不应该是第一段代码中的@@var吗?我正在读David Black的《有良好基础的Rubyist》(the Well Grounded Rubyist)。Jean:不,如果我使用
@@var
,那么子类将覆盖父类。请参阅hobodave的链接。具体来说,示例中“2”是如何重写的。事实并非如此,因为每次创建子类时都必须重写初始化。这不是很有用。在我的示例中,在initialize中包含一些代码可能更好。不,不完全是这样。你不是在做鳟鱼。新的或鲑鱼。最后是新的。您正在使用类本身。我想让实例得到类变量。@Doctor--现在怎么样?是的。我认为它现在在功能上等同于我给出的答案。您只是手动编写访问器。必须编写访问器:所有实例变量都是私有的,
attr.*
方法应用于实例对象而不是类对象。键入:
fish.foo
实际上应该是
fish.var
,没有。我没有定义“foo”,但关键是Ruby解释器会将“fish”视为调用的接收者,并将“self”设置为“fish”,以便解析引用。不过为了清晰起见,我添加了foo方法。调用'fish.var'会抛出一个命名错误。
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