局部变量,实例变量,self 都是绑定在对象上的名字,我们简称为绑定 (binding)。所有绑定都有一个寄居场所,我们称为作用域 (scope)。假设你是一个调试器,你时刻都处于一个作用域中,上下左右都是绑定:局部变量,实例变量,全局变量,常亮,还有当前对象 self。只有当你遇到三个关键字时,才会进入一个新作用域。
这三个改变作用域的关键字,分别是module
,class
和def
。我们称为作用域的门 (scope gate)。
在 Java 等其他语言里,一个作用域内可以看到外围作用域内的变量,但 Ruby 不同,一个作用域内只能看到当前作用域内的变量。也就是说,变量不能跨作用域查找。
比如:
scope = "main scope"
class Example
puts scope # => 输出undefined local variable or method `scope' for Example:Class (NameError)
end
再比如:
class Example
@scope = "class scope"
def hello
puts @scope # => 输出 ""
end
end
任何时候都有一个当前对象,当不在任何类和方法调用中时,当前对象是 main 对象,有时称为顶级上下文 (top level context)。实例变量都会定义在当前对象上,因此在顶级上下文中定义的实例变量都会定义在 main 对象上:
@var = "main instance variable"
self.instance_variables # => 输入 [:@var]
在顶级上下文中定义的方法都会成为 Object 类的私有方法,因为 Object 是所有类的基类,所以在顶级上下文中定义的方法会成为所有类的私有方法:
def foo
puts "method defined in top level context"
end
class Example
def my_method
foo
end
end
Example.new.my_method # => 输出 "method defined in top level context"
要打破 scope 的阻隔,需要用 ruby 内建的方法模拟这三个关键字来定义 module,class 或 method:
比如Class.new()
和Module.new
方法来模拟class
和module
:
my_var = "Success"
MyClass = Class.new do
puts my_var # => 输出 "Sucess"
end
比如Module#define_method()
方法来模拟def
:
my_var = "Success"
MyClass = Class.new do
define_method :my_method do
puts my_var
end
end
MyClass.new.my_method # => 输出 "Success"