2013-04-14 152 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]