2013-04-14 249 views
0

我希望有人能夠對我在下面收到的錯誤有所瞭解。我在Node父類中定義一個實例變量,要訪問並修改它的子類AddSubNode,每當我嘗試訪問@code我收到此錯誤:子類中的實例變量訪問

'code': undefined method `<<' for nil:NilClass (NoMethodError) 

我必須誤解Ruby的繼承模型,但我認爲我可以做到這一點。

class Node 
    attr_accessor :code 

    def initialize 
    @code = [] 
    end 
end 

class AddSubNode < Node 
    def initialize op, l, r 
    @op = op 
    @l = l 
    @r = r 
    end 

    def code 
    @code << 1 # error: `code': undefined method `<<' for nil:NilClass (NoMethodError) 
    @code 
    end 

    def to_s 
    "#{@l} #{@op} #{@right}" 
    end 
end 

回答

4

您需要在子類的初始化程序中調用超級初始值設定項。

class AddSubNode < Node 
    def initialize op, l, r 
    super() 
    @op = op 
    @l = l 
    @r = r 
    end 
... 

編輯:忘記括號

+0

有趣的是,由於某種原因,我認爲這是隱式完成的。謝謝! –

+0

不,Ruby中的方法不會隱式地調用它們的超類實現。這沒有意義,也沒有其他語言。我可以問*爲什麼*你認爲? –

+0

@JörgWMittag對於我來說這似乎是一個理想的功能,在這種特殊情況下,我有〜100個「Node」的子類,我不得不每次回去添加'super()'。你能否給出一個理由說明爲什麼這會發生隱含的意義? –

2

當你重新定義initialize方法在子類中,覆蓋原來的。因此實例變量@code從不初始化,並且當您調用@code << 1時,您的代碼會引發錯誤。

從子類中的initialize方法調用super()(有效地調用它的父代)或使用@code << 1 unless @code.nil?是解決錯誤的幾種方法。

+0

這沒有意義。 –

+0

@HunterMcMillen你不瞭解它嗎? – rudolph9

+1

魯道夫的意思是,子類自動繼承了超級初始化器(通常被稱爲)。但是在子類中使用'def初始化op,l,r',可以用新的實現覆蓋它。 – tessi

1

在這裏,我只是試圖給你一些可視化測試這種情況。

class Node 
    attr_accessor :code 

    def initialize 
    @code = [] 
    end 
end 

class AddSubNode < Node 
    def initialize op, l, r 
    @op = op 
    @l = l 
    @r = r 
    end 

    def code 
    @code << 1 # error: `code': undefined method `<<' for nil:NilClass (NoMethodError) 
    @code 
    end 

end 

ob = AddSubNode.new(1,2,3) 
p ob.instance_variables #=> [:@op, :@l, :@r] 
p ob.instance_variable_defined?(:@code) #=> false 
p ob.instance_variable_set :@code,[12] #=> [12] 
p ob.instance_variable_defined?(:@code) #=> true 
p ob.instance_variable_get :@code #=> [12] 
p ob.instance_variables #=> [:@op, :@l, :@r, :@code] 
p ob.code #=> [12, 1]