全局变量以$开头,它是全局可见的。Ruby 内建的全局变量如$:
和$LOAD_PATH
表示 require 读取文件时寻找的目录数组。
类变量以@@开头,可被定义它的类以及其子类访问,也可被定义它的类和子类的实例访问。
class Example
@@cls_var = "defined in Example"
def self.cls_var
@@cls_var
end
def inst_var
@@cls_var
end
end
puts Example.cls_var # => "defined in Example"
puts Example.new.inst_var # => "defined in Example"
class SubExample < Example
@@cls_var = "modified in SubExample"
end
puts SubExample.cls_var # => "modified in SubExample"
puts SubExample.new.inst_var # => "modified in SubExample"
class variable 并不真正属于类,而是属于类体系结构。
@@cls_var = 1
class Example
@@cls_var = 2
end
puts @@cls_var # => 2
因为@@cls_var
被定义在 Object 类上,而 Example 继承自 Object,所以 Example 也共享了这个类变量。
class Example
@@foo = ""
def foo
@@foo
end
end
class SubExample < Example
@@foo = "hello"
end
puts Example.new.foo # => "hello
Example.new 并不属于 SubExample,竟然也被 SubExample 的修改所影响!
正因为很多地方都可以改变类变量,很难追踪是什么地方做了改变,所以不推荐使用它。
在类对象上定义的变量是实例变量,以@开头,实例变量因为存在于在对象上,所以整个对象的类的继承链都可以使用。这与 Java 等静态语言不一样。
父类里定义的实例变量,子类方法可以使用:
class Example
def def_inst_var
@inst_var = "I am defined in Example"
end
end
class SubExample < Example
def inst_var
@inst_var
end
end
sub = SubExample.new
sub.def_inst_var
puts sub.inst_var # => "I am defined in Example"
子类里定义的变量,父类方法也可以使用:
class Example
def inst_var
@inst_var
end
end
class SubExample < Example
def def_inst_var
@inst_var = "I am defined by SubExample"
end
end
sub = SubExample.new
sub.def_inst_var
puts sub.inst_var # => "I am defined by SubExample"
类本身也是一种对象,它是 Class 类的实例,在类上定义的变量,叫类实例变量。类实例变量只能被类方法访问。
class Example
@cls_inst_var = "class instance variable"
def self.cls_inst_var
@cls_inst_var
end
end
puts Example.cls_inst_var # => "class instance variable"
类实例变量因为存放在类对象上,所以能够被继承链上的类方法访问到。比如子类定义的类实例变量,父类的类方法也能访问:
class Example
def self.cls_inst_var
@cls_inst_var
end
end
class SubExample < Example
@cls_inst_var = "class instance variable"
end
puts SubExample.cls_inst_var # => "class instance variable
局部变量只属于当前的作用域,作用域的改变只取决于三个关键字:class
, module
和def
。跟 Java 等语言不同,for,if,while 等关键字并不会改变作用域。
def test(ok)
if ok
a = "I am OK!"
end
puts a
end
test(false) # => ""
test(true) # => "I am OK!"