我的印象是Ruby中的类定义可以重新打开:
class C
def x
puts 'x'
end
end
class C
def y
puts 'y'
end
end
这按预期工作,y
被添加到原始类定义中。
我很困惑为什么以下代码无法正常工作:
class D
x = 12
end
class D
puts x
end
这将导致NameError
例外。为什么在重新打开课程时会启动新的本地范围?这似乎有点违反直觉。在扩展类时,有没有办法继续以前的本地范围?
答案 0 :(得分:8)
本地变量与对象无关,它们与范围相关联。
局部变量是词法范围的。你要做的事情不再有效:
def foo
x = :hack if false # Ensure that x is a local variable
p x if $set # Won't be called the first time through
$set = x = 42 # Set the local variable and a global flag
p :done
end
foo #=> :done
foo #=> nil (x does not have the value from before)
#=> done
在上面,它是同一个对象的同一个方法,它被执行两次。 self
没有变化。但是,在调用之间清除局部变量。
重新打开该类就像再次调用一个方法:您处于相同的self
范围内,但是您正在启动一个新的本地上下文。当您使用class D
关闭end
块时,您的本地变量将被丢弃(除非它们是closed over)。
答案 1 :(得分:6)
在ruby中,局部变量只能在定义它们的范围内访问。但是,class
关键字会导致全新的范围。
class D
# One scope
x = 12
end
class D
# Another scope
puts x
end
因此,您无法访问第一个class
部分中定义的局部变量,因为当您离开第一个范围时,其中的局部变量将被销毁,内存将被垃圾收集释放。
例如,def
也是如此。
答案 2 :(得分:0)
简单的解决方案是将 x 设为class instance variable。当然,这不能回答你的范围问题。我认为 x 不在重新打开的类的scope(参见检测Ruby变量的范围)的原因是因为它的范围从未首先是 D 类的。 x 的范围在类 D 关闭时结束,因为 x 既不是实例变量也不是类变量。
我希望有所帮助。
答案 3 :(得分:0)
这种行为有意义的部分原因在于元编程功能;您可以使用一些临时变量来存储可用于命名新常量的数据,或引用方法名称:
class A
names, values = get_some_names_and_values()
names.each_with_index do |name, idx|
const_set name, value[idx]
end
end
或许,你需要获得本征类......
class B
eigenclass = class << self; self; end
eigenclass.class_eval do
...
end
end
每次重新打开一个类都有一个新的作用域是有道理的,因为在Ruby中你经常在一个类定义中编写代码,这个代码是要执行的实际代码,而打开类只是一个为self
获得正确价值的方法。您不希望这些变量污染类的内容,否则您将使用类实例变量:
class C
@answer = 42
end
class C
p @answer
end