22

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

我如何在红宝石中做同样的事情?

4

5 回答 5

21

为了对比@khellll 的答案,这使用了 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"
于 2010-01-18T14:49:54.210 回答
8

@var上面提到的称为类实例变量,它与实例变量不同......阅读答案here以查看差异。

无论如何,这是等效的 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
于 2010-01-18T08:21:51.080 回答
4

Here's the version I ended up figuring out using hobodave's link:

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

Notice that subclassing only requires adding an @var -- no need to override initialize.

于 2010-01-18T16:57:02.887 回答
2

这也是 Java 编码人员使用 Ruby 时常犯的错误,也是我必须弄清楚的重大概念跳跃之一。起初它看起来很奇怪,但它确实是 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 是实例变量的原因。

于 2010-01-18T14:57:14.180 回答
1

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

于 2012-09-14T17:57:24.393 回答