Ruby Ruby 的作用域和作用域门

kevinclcn · 2015年08月07日 · 最后由 kevinclcn 回复于 2015年10月17日 · 5872 次阅读

局部变量,实例变量,self 都是绑定在对象上的名字,我们简称为绑定 (binding)。所有绑定都有一个寄居场所,我们称为作用域 (scope)。假设你是一个调试器,你时刻都处于一个作用域中,上下左右都是绑定:局部变量,实例变量,全局变量,常亮,还有当前对象 self。只有当你遇到三个关键字时,才会进入一个新作用域。

这三个改变作用域的关键字,分别是module,classdef。我们称为作用域的门 (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方法来模拟classmodule:

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"

刚开始看到第二个类实例变量的例子还没反应过来

你好,想问一下,既然 def 是一个 scope gate,为什么在类方法中还可以给类变量赋值呢?这不是跨作用域了吗?

#2 楼 @viciousstar 类方法对应的 self 是类,所以类方法能看到类变量。

4 楼 已删除
luxious 不写在 class 中的 self 是什么? 提及了此话题。 09月05日 15:52
需要 登录 后方可回复, 如果你还没有账号请 注册新账号