2016-10-24 14 views
1

@pointsの代わりに@@pointsというクラス変数を使用しているときに、この短いコードが動作しています。なぜこのように起こっているのだろうか?誰かが私を説明することができますか? @pointsは常にnilのようです。なぜこのインスタンス変数が増分していないのですか?

class Game 

    @points = 0 

    def start 

    until @points == 10 
     puts "Guess number between 0 and 10:" 
     num = gets.chomp.to_i 
     break if @points == 0 
     guess_number(num) 
     puts "Your score is: #{@points}" 

    end 

    end 

    def guess_number(num) 
    @points += 1 if num == rand(0..10) 
    end 

end 

game = Game.new 
game.start 
+0

極小点: 'gets.chomp.to_i'は' chomp': 'gets.to_i'なしで書かれることがよくあります。 '' 123 ".to_i'、' '123 \ n" .to_i'と '' 123X456abc ".to_i'はすべて' 123'を返します。 [String#to_i](http://ruby-doc.org/core-2.3.0/String.html#method-i-to_i)を参照してください。「有効な数字の最後を過ぎた余分な文字は無視されます。 " –

答えて

2

@pointsは、クラスのインスタンス変数である、とインスタンスメソッドのスコープ内からアクセスしているので、あなたは

self.class.instance_variable_get(:@points) 

またはattr_accessorGame中のsingleton_class

を定義を行うにはいずれかがあるだろう
class Game; class << self; attr_accessor :points; end; end 

とすると、できるでしょう

self.class.points 

しかし、どちらもあなたが本当に望むものではありません。

私はあなたがインスタンスメソッドの範囲内からクラス変数へのアクセスを持っていないので、それは働いているクラス変数@@points代わりの @points

を使用していたときにコードが働いています。言ったように

それは、クラスのインスタンス変数を使用すると、@points変数インスタンスを定義したことがないので@pointsは、常にnil

それは常にnilであるように見えますが、。

したがって、これら三つのことは(あなたはRubyのスコープについて何かを読むことができる - ARスコープを混在させないでください)異なっている: 変数

  • クラス変数
  • クラスインスタンス変数
  • インスタンス

    解決方法はたくさんありますが、インスタンスレベルでそれを保持したい場合は、をメソッドに置き換えます。

    def points 
        @points ||= 0 
    end 
    

    そして、これをpointsとして使用してください。これで、期待通りに機能します。

+0

OPがクラス外にポイントを公開したくない場合は、 '@points = 0'を設定するコンストラクタを実装する方が簡単でしょうか? – pjs

+0

@pjs私が言ったように、いくつかの方法でそれをやめるので、選択するのはOPになりますが、もちろんです。 –

+0

クラスインスタンス変数の値は、これは 'self.class.instance_variable_get(:@ points)'(あなたがよく知っているように)で行うことができるので、インスタンスのスコープ内で取得する必要があります。 –

0

Andrey Deinekoのおかげで、ここでは、インスタンス変数を使用するためのそのようなソリューションを考え出しました。

class Game 

    def initialize 
    @points = 0 
    end 

    def start 

    until points == 10 
     puts "Guess number between 0 and 10:" 
     num = gets.chomp.to_i 
     break if points == 10 
     guess_number(num) 
     puts "Your score is: #{points}" 

    end 

    end 

    private 

    def guess_number(num) 
    if num == rand(0..10) 
     increment_points 
    end 
    end 

    def points 
    @points 
    end 

    def increment_points 
    @points += 1 
    end 

end 

game = Game.new 
game.start 
+0

このアプローチの危険性は、あなたのクラスを覗き込んだユーザは、ゲームをプレイすることなく直接「increment_points」を呼び出すことができるということです。インスタンス変数を使用する場合は、 'Game.new'インスタンスを作成するときに' @ points'を0に初期化するクラスに 'initialize'メソッドを追加してください。 – pjs

+0

良いアイデアのようです。私はanwserを編集し、私はいくつかのメソッドを非公開にしました。 –

+0

また、ゲッターにattr_readerの名前以外の名前を付けて標準的なRuby標準を覆すこともあります。ちょうど考慮すべき何か。 –

関連する問題