2013-11-21 195 views
3

我最近一直在用下面的代碼難住了:紅寶石attr_reader和+ =

class Foo 
    attr_accessor :n 

    def initialize(i) 
    @n = i 
    end 

    def val 
    n 
    end 

    def bump! 
    n += 1 
    end 
end 

f = Foo.new(0) 

puts f.val 
f.bump! 

puts f.val成功,並打印出0預期。 f.bump!導致以下NoMethodError

foo.rb:13:in `bump!': undefined method `+' for nil:NilClass (NoMethodError) 
     from foo.rb:20:in `<main>' 

任何想法,爲什麼n是在表達n += 1nil

使用n = 1 + n而是提出了一個TypeErrornil cannot be coerced into Fixnum),所以n其實nil

+0

FWIW,我不認爲attr_accessor在類中使用是有道理的,也許更好的辦法是在每個地方使用@foo?可能它甚至沒有得到支持。 – Smar

回答

7

即使你已經定義的n=方法Foo,紅寶石不會讓你從稱之爲內類沒有明確的接收器即self.n=

所以,當你寫n += 1,這被翻譯成n = n + 1n=沒有明確的接收器,所以Ruby創建了一個局部變量n(它是nil)。因此,nn + 1是指nil局部變量,給你NoMethodError

僅供參考,你不需要attr_accessor,除非你想要n可以訪問以外的的類!即使這樣,當你編寫實例方法時,你應該使用普通的實例變量@n

+0

很好的解釋!謝謝!我不會寫這樣的東西,只是在重構一個有很好理由導出訪問器的類時偶然發現它。 –

+2

我認爲還值得一提的是,Ruby需要一個接收器的原因是爲了允許像這樣創建局部變量。否則,在定義'attr_writer'後就不可能創建一個局部變量。 – Max

1

你的錯誤有:

def bump! 
    n += 1 
end 

使用self.n。或者@n

當你這樣做:

attr_accessor :n 

其實你這樣做:

def n 
    @n 
end 

def n=(value) 
    @n= value 
end 

當你這樣做n += 1,您使用本地變量(爲零),而不是使用兩種方法由attr_accessor創建。

+0

'@n + = 1'和'self.n + = 1'都可以工作。但這不是問題。 @多米尼克:這是讀者的一部分失敗,而不是任務。 –

+0

是的,我只是想通了。謝謝;-) –

+0

>你使用一個局部變量(這是niL) **這是**的問題。 :-)爲什麼在'#bump!'裏面'n'' nil'而不在'#val'裏面'nil'? –