2016-10-24 60 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總是nil

它始終是nil,因爲你從來沒有定義的變量@points的實例,但是,正如所說,類實例變量。

所以這三樣東西是不同的(你可以閱讀了一些關於Ruby的作用域 - 不與AR範圍混合):

  • 類變量
  • 類實例變量
  • 實例變量

要解決這個問題,有很多方法,但是如果您想將其保留在實例級別,請將@points換成方法:

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'實例時,將'initialize'方法添加到'@points'初始化爲0的類中。 – pjs

+0

這似乎是個好主意。我編輯了我的anwser,並且我還私下做了一些方法。 –

+0

你也通過命名getter的東西來顛覆規範的Ruby標準,而不是attr_reader命名它的東西。只是需要考慮。 –

相關問題