新手总数:红宝石中的实例变量? [英] Total newbie: Instance variables in ruby?
问题描述
请原谅新手问题,但为什么@game_score总是为零?
Pardon the total newbiew question but why is @game_score always nil?
#bowling.rb
class Bowling
@game_score = 0
def hit(pins)
@game_score = @game_score + pins
end
def score
@game_score
end
end
推荐答案
让我们遍历代码,好吗?
Let's walk through the code, shall we?
#bowling.rb
class Bowling
@game_score = 0 # (1)
在这一点上(1),我们仍然在 class Bowling
之内.请记住:类就是与其他对象一样的对象.因此,此时,您要将0
分配给类对象Bowling
的实例变量@game_score
.
At this point (1), we are still inside the class Bowling
. Remember: classes are just objects like any other. So, at this point you are assigning 0
to the instance variable @game_score
of the class object Bowling
.
def hit(pins)
@game_score = @game_score + pins # (2)
现在(2),我们在Bowling
类的 instance方法中.即:这是一种将属于@game_score
属于Bowling
类的 instance ,而不是类本身.
Now (2), we are inside an instance method of the Bowling
class. I.e.: this is a method that is going to belong to an instance of Bowling
. So, now the instance variable @game_score
belongs to an instance of the Bowling
class, and not to the class itself.
由于此实例变量从未初始化为任何内容,因此它将求值为nil
(在Ruby中,未初始化的变量始终为nil
),因此其求值为@game_score = nil + pins
,并且nil
没有#+
方法,这将导致引发NoMethodError
异常.
Since this instance variable is never initialized to anything, it will evaluate to nil
(in Ruby, uninitialized variables always evaluate to nil
), so this evaluates to @game_score = nil + pins
and since nil
doesn't have a #+
method, this will result in a NoMethodError
exception being raised.
end
def score
@game_score # (3)
在这里(3),我们再次位于Bowling
类的 instance方法中.由于我上面概述的原因,它始终会评估为nil
:@game_score
从未初始化,因此它的评估结果为nil
.
And here (3), we are again inside an instance method of the Bowling
class. This will always evaluate to nil
, for the reason I outlined above: @game_score
is never initialized, therefore it evaluates to nil
.
end
end
我们可以使用Ruby的反射功能来查看发生了什么:
We can use Ruby's reflection capabilities to take a look at what's going on:
p Bowling.instance_variable_get(:@game_score) # => 0
b = Bowling.new
p b.instance_variable_get(:@game_score) # => nil
现在让我们将一个值注入实例变量:
Now let's inject a value into the instance variable:
b.instance_variable_set(:@game_score, 1)
p b.score # => 1
b.hit(3)
p b.score # => 4
因此,我们看到一切正常,我们只需要弄清楚如何确保实例变量被初始化即可.
So, we see that everything works as it should, we only need to figure out how to make sure the instance variable gets initialized.
为此,我们需要编写一个初始化方法.奇怪的是,初始化器方法实际上是称为initialize
的私有 instance方法. (为什么initialize
是实例方法而不是类方法的原因实际上很简单.Ruby将对象创建分为两个阶段:内存分配和对象初始化.内存分配由 class 完成. alloc
方法和对象初始化由称为initialize
的 instance 方法完成(Objective-C程序员会认识到这一点).alloc
是类方法的原因很简单:此时执行尚无实例,而initialize
是实例方法的原因是对象初始化显然是针对每个对象的;为方便起见,有一个称为new
的标准工厂类方法,它同时调用了这两种方法. alloc
和initialize
).
To do that, we need to write an initializer method. Strangely, the initializer method is actually a private instance method called initialize
. (The reason why initialize
is an instance method and not a class method, is actually quite simple. Ruby splits object creation in two phases: memory allocation and object initialization. Memory allocation is done by a class method called alloc
and object initialization is done by an instance method called initialize
. (Objective-C programmers will recognize this.) The reason why alloc
is a class method is simply that at this point in the execution there is no instance yet. And the reason that initialize
is an instance method is that object initialization is obviously per-object. As a convenience, there is a standard factory class method called new
that calls both alloc
and initialize
for you.)
class Bowling
def initialize
@game_score = 0
end
end
让我们对此进行测试:
c = Bowling.new
p c.score # => 0
c.hit(2)
p c.score # => 2
顺便说一句:Ruby的一些小技巧:缩进是2个空格,而不是1个制表符.而您的hit
方法更习惯于使用@game_score += pins
.
BTW: just some minor Ruby style tips: indentation is 2 spaces, not 1 tab. And your hit
method would more idiomatically be @game_score += pins
.
这篇关于新手总数:红宝石中的实例变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!