新手总数:ruby中的实例变量?

请原谅新的总体问题,但为什么@game_score总是为零呢?

#bowling.rb class Bowling @game_score = 0 def hit(pins) @game_score = @game_score + pins end def score @game_score end end 

让我们来看看代码,好吗?

 #bowling.rb class Bowling @game_score = 0 # (1) 

在这一点上(1),我们仍然在Bowling class内。 记住:类就像其他任何对象一样。 因此,此时您将0分配给类对象Bowling的实例变量@game_score

  def hit(pins) @game_score = @game_score + pins # (2) 

现在(2),我们在Bowling类的实例方法中。 即:这是一种属于Bowling 实例的方法。 所以,现在实例变量@game_score属于Bowling类的一个实例@game_score属于类本身。

由于这个实例变量永远不会被初始化为任何东西,它将评估为nil (在Ruby中,未初始化的变量总是计算为nil ),因此这将评估为@game_score = nil + pins ,因为nil没有#+方法,将导致引发NoMethodErrorexception。

  end def score @game_score # (3) 

在这里(3),我们再次在Bowling类的实例方法中。 这总是评估为nil ,因为我上面概述的原因: @game_score永远不会被初始化,因此它的计算结果为nil

  end end 

我们可以使用Ruby的reflectionfunction来查看正在发生的事情:

 p Bowling.instance_variable_get(:@game_score) # => 0 b = Bowling.new p b.instance_variable_get(:@game_score) # => nil 

现在让我们在实例变量中注入一个值:

 b.instance_variable_set(:@game_score, 1) p b.score # => 1 b.hit(3) p b.score # => 4 

所以,我们看到一切都按预期工作,我们只需要弄清楚如何确保实例变量被初始化。

为此,我们需要编写初始化方法。 奇怪的是,初始化方法实际上是一个名为initialize的私有实例方法 。 ( initialize是实例方法而不是类方法的原因实际上非常简单.Ruby分两个阶段创建对象:内存分配和对象初始化。内存分配由一个名为alloc方法完成,对象初始化由一个名为initialize实例方法。(Objective-C程序员会认识到这一点。) alloc是一个类方法的原因很简单,就是在执行的这一点上还没有实例。而initialize是一个实例方法的原因是对象初始化显然是每个对象。为方便起见,有一个名为new的标准工厂类方法,它为你调用allocinitialize 。)

 class Bowling def initialize @game_score = 0 end end 

我们来测试一下:

 c = Bowling.new p c.score # => 0 c.hit(2) p c.score # => 2 

BTW:只是一些小的Ruby风格提示:缩进是2个空格,而不是1个标签。 而你的hit方法更像是@game_score += pins

因为你没有

 def initialize @game_score = 0 end 

类定义中的赋值没有按照您的想法执行,并且当调用hit时,它不能添加到nil

如果你现在问@game_score发生了@game_score 好吧,永远记得Class是一个对象Object是一个类

Ruby类具有这种类似Zen的“真实”存在的方式很酷。 Ruby并不精确地具有命名类,而是类名是对类Class对象的引用。 通过在实例方法之外分配@game_score ,您创建了一个类实例变量 ,类对象Bowling一个属性,它是类Class一个实例。 通常,这些对象非常有用。 (参见第1章, Ruby Way ,Hal Fulton。)

@game_score定义了一个名为类的实例变量 ,它是为单例类对象定义的变量:

 class << Bowling attr_accessor :game_score end Bowling.game_score #=> 0 

这可以与为实例对象定义的普通实例变量区别开来。

@game_score永远不会在这里得到零值 – 你需要把它放在初始化中,如同

def初始化@game_score = 0结束