这部分代码动态创建了几个类:
(1..MAX_ACT).each do |act_id|
klass = Class.new(ActB) do
def initialize(trg)
super(trg, act_id)
end
end
Object.const_set("Act#{act_id}", klass)
end
在这种情况下,公共基类(ActB
)的构造函数带有两个参数,而子类的构造函数带有一个参数。
运行此代码效果很好,但是例如,当我稍后尝试实例化这些类之一时,
Act3.new(4)
我收到错误消息
NameError: undefined local variable or method `act_id' for #<Act3:0x00000006008b7990>
错误消息必须引用该行
super(trg, act_id)
因为这是程序中我使用的唯一位置。但是,此变量在上面说了几行时就定义了
(1..MAX_ACT).each do |act_id|
我曾期望, do ... end 块为绑定 act_id 的构造函数创建一个闭合。但是,情况似乎并非如此。
为什么我的示例不起作用?我该如何正确做?
答案 0 :(得分:4)
def
(以及class
和module
)创建一个新的本地范围,该范围不会从外部继承任何本地变量。
因此,您对Class.new do .. end
创建了一个闭包是正确的……但是内部def
不共享它。
如果您需要标准块行为,则可以改用define_method
:
(1..MAX_ACT).each do |act_id|
klass = Class.new(ActB) do
define_method :initialize do |trg|
super(trg, act_id)
end
end
Object.const_set("Act#{act_id}", klass)
end
答案 1 :(得分:1)
出于好奇,这里有一个黑客,可以愚弄作用域并仍然使用def initialize
:)
class ActB
def initialize(trg, act_id)
puts "ActID: #{act_id}"
end
end
(1..MAX_ACT).each do |act_id|
klass = Class.new(ActB) do
@act_id = act_id
def initialize(trg)
super(trg, self.class.instance_variable_get(:@act_id))
end
end
Object.const_set("Act#{act_id}", klass)
end
Act1.new :foo
#⇒ ActID: 1
Act2.new :foo
#⇒ ActID: 2
答案 2 :(得分:0)
这里的问题是传递给Class.new
的块是在该类的上下文中执行的。在该类的上下文中,未定义act_id
。因此,要解决此问题,可以将方法定义移到类初始化之外,如下所示:
(1..MAX_ACT).each do |act_id|
klass = Class.new(ActB)
klass.define_method(:initialize) do |trg|
super(trg, act_id)
end
Object.const_set("Act#{act_id}", klass)
end