13

まったくの初心者の質問で申し訳ありませんが、@game_score が常に nil なのはなぜですか?

#bowling.rb

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

    def score
        @game_score
    end
end
4

4 に答える 4

37

コードを見ていきましょう。

#bowling.rb

class Bowling
  @game_score = 0 # (1)

この時点 (1) では、まだクラス Bowling内にいます。覚えておいてください: クラスは他のオブジェクトと同じように単なるオブジェクトです。したがって、この時点でクラス object0のインスタンス変数に代入しています。@game_score Bowling

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

(2) では、クラスのインスタンス メソッドの内部にいます。つまり、これは のインスタンスBowlingに属するメソッドです。したがって、インスタンス変数は、クラス自体ではなく、クラスのインスタンスに属します。Bowling@game_scoreBowling

このインスタンス変数は何にも初期化されないため(nil Ruby では、初期化されていない変数は常に に評価されますnil)、これは に評価され@game_score = nil + pins、メソッドnilがないため、例外が発生します。#+NoMethodError

 end
 def score
  @game_score # (3)

ここ (3) では、再びクラスのインスタンス メソッド内にいます。これは、上で概説した理由により、Bowling常に と評価されます。初期化されないため、 と評価されます。nil@game_scorenil

 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はオブジェクト生成をメモリ割り当てとオブジェクト初期化の2段階に分けています。メモリ割り当ては呼び出されたクラスメソッドによって行われalloc、オブジェクトの初期化はインスタンスによって行われます。 (Objective-C プログラマーはこれに気付くでしょう。) なぜクラスメソッドなのinitializeかという理由allocは、実行のこの時点ではまだインスタンスがないからです。initializeインスタンスメソッドであるということは、オブジェクトの初期化が明らかにオブジェクトごとであることです。new便宜上、 と の両方を呼び出す標準ファクトリ クラス メソッドがallocありinitializeます。)

class Bowling
 def initialize
  @game_score = 0
 end
end

これをテストしましょう:

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

ところで: ちょっとした Ruby スタイルのヒント: インデントは 1 つのタブではなく 2 つのスペースです。そして、あなたのhit方法はより慣用的に@game_score += pins.

于 2009-10-10T20:24:58.903 に答える
16

あなたが持っていないので

def initialize
  @game_score = 0
end

クラス定義の割り当ては、あなたが思っていることをしていません。hit呼び出されたときに、に追加することはできませんnil

あなたが今、何が起こったのか尋ねたら@game_score、ええと、 Class は objectであり、Object は classであることを常に覚えておいてください。

Ruby クラスがこの禅のような「本物の」存在を持っている方法は、とてもクールです。Ruby には名前付きのクラスが正確に存在するわけではありません。むしろ、クラス名は class のオブジェクトへの参照ですClass@game_scoreインスタンス メソッドの外側に代入することにより、クラス オブジェクトの属性であるクラス インスタンス変数Bowlingを作成しました。これは、クラスのインスタンスですClass。一般に、これらのオブジェクトはあまり役に立ちません。(Chapter 1, The Ruby Way、Hal Fulton を参照してください。)

于 2009-10-10T18:17:54.993 に答える
9

@game_scoreそこで定義されているのは、クラスインスタンス変数と呼ばれるものです。これは、シングルトンクラスオブジェクト用に定義された変数です。

class << Bowling
  attr_accessor :game_score
end

Bowling.game_score #=> 0

これは、インスタンスオブジェクトに対して定義された通常のインスタンス変数とは異なることがわかるためです。

于 2009-10-10T18:19:15.053 に答える
0

@game_scoreがここでゼロの値を取得することはありません-次のように、initialize内に配置する必要があります

def initialize @game_score = 0 end

于 2009-10-10T18:19:52.057 に答える