新手入门:ruby 中的实例变量?

发布于 2024-08-06 20:39:15 字数 224 浏览 4 评论 0原文

请原谅这个新手问题,但为什么 @game_score 总是为零?

#bowling.rb

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

    def score
        @game_score
    end
end

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

又怨 2024-08-13 20:39:15

让我们看一下代码,好吗?

#bowling.rb

class Bowling
  @game_score = 0 # (1)

此时 (1),我们仍然位于 class Bowling 中。请记住:类与其他对象一样只是对象。因此,此时您将 0 分配给类对象 Bowling 的实例变量 @game_score

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

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

由于 this 实例变量从未初始化为任何内容,因此它将计算为 nil(在 Ruby 中,未初始化的变量始终计算为 nil),因此计算结果为 @game_score = nil + pin 并且由于 nil 没有 #+ 方法,这将导致 NoMethodError 引发异常。

 end
 def score
  @game_score # (3)

在这里 (3),我们再次位于 Bowling 类的实例方法中。由于我上面概述的原因,它的计算结果始终为 nil@game_score 从未初始化,因此它的计算结果为 nil

 end
end

我们可以使用 Ruby 的反射功能来看看发生了什么:

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

顺便说一句:只是一些小的 Ruby 风格提示:缩进是 2 个空格,而不是 1 个制表符。而你的 hit 方法更惯用的是 @game_score += pin

Let's walk through the code, shall we?

#bowling.rb

class Bowling
  @game_score = 0 # (1)

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)

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.

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)

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

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.

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

Let's test this:

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

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.

自此以后,行同陌路 2024-08-13 20:39:15

因为您没有

def initialize
  @game_score = 0
end

类定义中的赋值没有执行您认为它正在执行的操作,并且当调用 hit 时,它无法添加到 nil

如果您现在问@game_score发生了什么?,那么,请永远记住类是一个对象对象是一个类。

Ruby 类拥有这种禅宗般的“真实”存在,这真是太酷了。 Ruby 并不精确地具有命名类,相反,类名是对类 Class 的对象的引用。通过在实例方法之外分配给 @game_score,您创建了一个类实例变量,它是类对象 Bowling 的一个属性,它是一个实例类Class。一般来说,这些对象不是很有用。 (请参阅第 1 章,The Ruby Way,Hal Fulton。)

Because you don't have

def initialize
  @game_score = 0
end

The assignment in the class definition is not doing what you think it is doing, and when hit gets invoked it can't add to nil.

If you now ask what happened to @game_score?, well, always remember Class is an object and Object is a class.

It's way cool the way Ruby classes have this Zen-like "real" existence. Ruby doesn't precisely have named classes, rather, class names are references to objects of class Class. By assigning to @game_score outside of an instance method you created a class instance variable, an attribute of the class object Bowling, which is an instance of class Class. These objects are not, in general, very useful. (See Chapter 1, The Ruby Way, Hal Fulton.)

残花月 2024-08-13 20:39:15

这里定义的@game_score被称为类实例变量,它是为单例类对象定义的变量:

class << Bowling
  attr_accessor :game_score
end

Bowling.game_score #=> 0

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

@game_score defined there is called class instance variable, which is a variable defined for the singleton class object:

class << Bowling
  attr_accessor :game_score
end

Bowling.game_score #=> 0

This is as you can tell different from the normal instance variables defined for instance objects.

菩提树下叶撕阳。 2024-08-13 20:39:15

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

def 初始化
@游戏分数 = 0
结尾

@game_score will never get a value of zero here - you need to put it inside initialize, as in

def initialize
@game_score = 0
end

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文