Hal*_*oDu 19 ruby oop ruby-on-rails
我正在开发一个小型应用程序,并且遇到了ruby的OOP模型的问题.我有以下简化的类结构.
class Foo
protected
@bar = []
def self.add_bar(val)
@bar += val
end
def self.get_bar
@bar
end
end
class Baz < Foo
add_bar ["a", "b", "c"]
end
Run Code Online (Sandbox Code Playgroud)
我现在的问题是,当我在Baz的类定义中调用add_bar时,@bar显然没有初始化,我得到一个+运算符不可用的错误nil.调用add_bar上Foo直接不会产生这个问题.为什么这样,我如何@bar正确初始化?
为了弄清楚我想要什么,我将指出我期望从这些类中获得的行为.
Foo.add_bar ["a", "b"]
Baz.add_bar ["1", "2"]
Foo.get_bar # => ["a", "b"]
Baz.get_bar # => ["a", "b", "1", "2"]
Run Code Online (Sandbox Code Playgroud)
我怎么能实现这个目标?
r00*_*00k 43
简短回答:实例变量不会被子类继承
更长的答案:问题是你@bar = []在类的主体中写了(在任何方法之外).设置实例变量时,它存储在当前的任何变量中self.当你在一个类体中时,self是类对象Foo.因此,在您的示例中,@foo在类对象Foo上定义.
稍后,当您尝试查找实例变量时,Ruby会查找当前的任何内容self.当您从Baz调用add_bar时,self是Baz.也self仍然是在巴兹add_bar的主体(即使该方法是在富).所以,Ruby @bar在Baz中寻找并找不到它(因为你在Foo中定义它).
这是一个可能使这个更清晰的例子
class Foo
@bar = "I'm defined on the class object Foo. self is #{self}"
def self.get_bar
puts "In the class method. self is #{self}"
@bar
end
def get_bar
puts "In the instance method. self is #{self} (can't see @bar!)"
@bar
end
end
>> Foo.get_bar
In the class method. self is Foo
=> "I'm defined on the class object Foo. self is Foo"
>> Foo.new.get_bar
In the instance method. self is #<Foo:0x1056eaea0> (can't see @bar!)
=> nil
Run Code Online (Sandbox Code Playgroud)
这无疑是有点令人困惑的,也是Ruby新手的常见绊脚石,所以不要感到难过.当我阅读编程Ruby(又名"The Pickaxe")中的"Metaprogramming"章节时,这个概念终于点击了我.
我如何解决你的问题:看看Rails的class_attribute方法.它允许你尝试做的事情(在父类中定义一个可以在其子类中继承(和覆盖)的属性).