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

Geo*_*uer 13 ruby instance-variables

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

#bowling.rb

class Bowling
  @game_score = 0
    def hit(pins)
        @game_score = @game_score + pins
    end

    def score
        @game_score
    end
end
Run Code Online (Sandbox Code Playgroud)

Jör*_*tag 37

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

#bowling.rb

class Bowling
  @game_score = 0 # (1)
Run Code Online (Sandbox Code Playgroud)

在这一点上(1),我们仍然在课堂上 Bowling.请记住:类只是与其他类似的对象.因此,此时您将分配0@game_score 类对象Bowling的实例变量.

 def hit(pins)
  @game_score = @game_score + pins # (2)
Run Code Online (Sandbox Code Playgroud)

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

由于实例变量永远不会初始化为任何东西,因此它将评估为nil(在Ruby中,未初始化的变量始终求值为nil),因此这将计算@game_score = nil + pins并且由于nil没有#+方法,这将导致NoMethodError引发异常.

 end
 def score
  @game_score # (3)
Run Code Online (Sandbox Code Playgroud)

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

 end
end
Run Code Online (Sandbox Code Playgroud)

我们可以使用Ruby的反射功能来查看正在发生的事情:

p Bowling.instance_variable_get(:@game_score) # => 0
b = Bowling.new
p b.instance_variable_get(:@game_score) # => nil
Run Code Online (Sandbox Code Playgroud)

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

b.instance_variable_set(:@game_score, 1)
p b.score # => 1
b.hit(3)
p b.score # => 4
Run Code Online (Sandbox Code Playgroud)

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

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

class Bowling
 def initialize
  @game_score = 0
 end
end
Run Code Online (Sandbox Code Playgroud)

我们来测试一下:

c = Bowling.new
p c.score # => 0
c.hit(2)
p c.score # => 2
Run Code Online (Sandbox Code Playgroud)

BTW:只是一些小的Ruby风格提示:缩进是2个空格,而不是1个标签.而且你的hit方法更具有惯用性@game_score += pins.


Dig*_*oss 16

因为你没有

def initialize
  @game_score = 0
end
Run Code Online (Sandbox Code Playgroud)

类定义中的赋值没有按照您的想法执行,并且在hit调用它时无法添加nil.

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

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


khe*_*lll 9

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

class << Bowling
  attr_accessor :game_score
end

Bowling.game_score #=> 0
Run Code Online (Sandbox Code Playgroud)

这与您为实例对象定义的普通实例变量不同.