在讲解变量之前首先我们要明白什么是作用域?
简单的理解就是作用域是寄居在一定的区域类,相当于一个寄居场所。
先举个例子:
class Parent
p self // numberone
def self.hello // numbertwo
p self
end
def world //numberthree
p self
end
end
Parent.hello
Parent.new.world
输出结果:
Parent
Parent
#<Parent:0x007fae7d81bf40>
看到这些结果应该就是我们想要的,其实我们可以把这些值当做是作用域那么我们就很清晰了:
numberone:作用域是Parent
numbertwo: 作用域是Parent
numberthree:作用域是#<Parent:0x007fae7d81bf40>
上面看起来有点奇怪,看下面例子:
class Parent
p self.class
def self.hello
p self.class
end
def world
p self.class
end
end
Parent.hello
Parent.new.world
输出结果:
Class
Class
Parent
通过结果说明了,Parent是Class的实例,#<Parent:0x007fae7d81bf40>
而这个是是Parent类的实例
好了,从上面我们总结下:
numberone: 作用域是Class实例的作用域
numbertwo:作用域是Class实例的作用域
numberthree:作用域是Parent实例的作用域
其实大家好奇我说这些有啥用了,下面见分晓
局部变量:局部变量只属于当前的作用域,以小写字母或者下划线开头
举例如下:
class Parent
local = "hello, world" //numberone
p local
def self.hello //nubertwo
p local
end
def world //nuberthree
p local
end
end
Parent.hello
Parent.new.world
输出结果
"hello, world"
undefined local variable or method `local' for Parent:Class (NameError)
分析一下,我们在numberone区域声明了局部变量,按照定义和作用域理解局部变量只属于numberone作用域,其他区域的都访问不了,其实这里有个疑惑,按照前面作用域的分析,numberone是Class实例的作用域,numbertwo也是属于Class实例作用域,为什么访问不了?
记住我前面说的,局部变量只会在当前的作用域内寻找,虽然numberone和numbertwo作用域是一样的,但是也是属于不同区域,就像在一个房间里面有床和桌子,其实 是在同一个房间这个作用域内。但是,numberone只会去床上找东西,numbertwo只会去桌子上找东西。
举个例子:
class Parent
p local //numberone
def self.hello
local = "hello, world" //numbertwo
p local
end
def world
p local //nuberthree
end
end
Parent.hello
Parent.new.world
输出结果:
undefined local variable or method `local' for #<Parent:0x007faffa873c80> (NameError)
其实这里直接就异常了,这里大家应该都知道,边解释边执行,解释到loca发现没找到就异常了,这里跟上个例子很想,只是我在numbertwo作用域定义了,为什么外面找不到我已经说了。numbertwo只会去房间这个作用域的桌子上去找,不会去床上了。
小结:记住局部变量只会到当前的区域去找,即使作用域相同,也只会去找作用域属于自己的区域。
实例变量:在类对象上定义的变量是实例变量,以@开头,实例变量因为存在于在对象上,即属于这个对象的这个作用域。
这个用的还是比较多的,先来个例子:
class Parent
@local = "hello, world" //numberone
p @local
def self.hello //numbertwo
p @local
end
def world //numberthree
p @local
end
end
Parent.hello
Parent.new.world
输出结果:
"hello, world"
"hello, world"
nil
好了我们来解释下,现在用作用域的概念来解释的话就好解释多了,实例变量是作用在这个对象上,只要是在这个对象的作用域类都能访问到实例变量,我们知道numberone和numbertwo都是Parent这个对象作用域,所以都可以访问到local了,而numberthree是作用在Parent这个对象实例的作用域肯定访问不到了,这里还有一点实例变量访问不到返回nil。
在看下面的例子:
class Parent
p @local //numberone
def self.hello
@local = "hello, world" //numbertwo
p @local
end
def world //numberthree
p @local
end
end
Parent.hello
Parent.new.world
输出结果:
nil
"hello, world"
nil
其实看到这个结果有点奇怪吧,按理说numberone和numbertwo作用域是一样的,作用的对象也是一样的,为啥第一个是nil,其实没什么奇怪的,ruby是解释型语言,不像Java是编译语言,在解释这个类的时候,方法并没有执行,@local是没有结果的所以为nil,我们还是举个例子吧,语言表达太苍白了,来,继续
class Parent
def self.hello
@local = "hello, world"
p @local
end
def world
p @local
end
Parent.hello
Parent.new.world
p @local
end
输出结果:
"hello, world"
nil
"hello, world"
这里我在类加载的时候调用了Parent.hello,相当于给Parent这个对象内置了实例变量@local = “hello, world”,这样@local就有值了,下面调用的时候就有值了,好了这里我就不多解释了,当然在外部想访问到这个实例变量,我们封装个方法就行了。
再来个例子:
class Parent
def self.hello //numberone
p @local
end
def world //numbertwo
@local = "hello, world"
p @local
end
Parent.new.world
Parent.hello
p @local //numberthree
end
输出结果:
"hello, world"
nil
nil
这里我们采用Parent.new.world,初始化了实例变量值,此时这个实例变量作用在了Parent.new这个对象上。也就是说这个对象的作用域都能访问到实例变量,为了证明这一点,举例如下:
class Parent
def self.hello
p @local
end
def world
@local = "hello, world"
p @local
end
def helloworld
p @local
end
Parent.new.world
Parent.new.helloworld
Parent.hello
p @local
end
输出结果:
"hello, world"
nil
nil
nil
输出的结果是让我惊讶的,为什么第二个值是nil, why??
其实我自己看下发现,Parent.new我们实例化了两次,其实@local是作用于第一个对象的,第二个已经是不同的对象 了,所以不可能有值了,好,那我们来修改下代码如下:
class Parent
def self.hello
p @local
end
def world
@local = "hello, world"
p @local
end
def helloworld
p @local
end
a = Parent.new
a.world
a.helloworld
Parent.hello
p @local
end
输出结果:
"hello, world"
"hello, world"
nil
nil
是我们想要的结果了。
小结:实例变量是作用在对象上,所以在这个对象的作用域都能找到这个实例变量,切记两次new,其实是不通的对象了
类变量:类变量以@@开头,可被定义它的类以及其子类访问,也可被定义它的类和子类的实例访问,作用在类上。
类变量在开发中我们用的很少,也尽量去好用,具体原因看下面解析
先举个例子;
class Parent
@@local = "helloworld" //numberone
p @@local
def self.hello //numbertwo
p @@local
end
def world //numberthree
p @@local
end
end
Parent.hello
Parent.new.world
输出结果:
"helloworld"
"helloworld"
"helloworld"
这个结果告诉我们在一个类中,不管是Class实例的作用域还是Parent实例的作用域我们都能找到类变量,从这点我们明白了,类变量是作用在类上,只要是这个类里面的,都能访问到。
看下面的例子:
class Parent
def self.hello
p @@local = "helloworld"
end
def world
p @@local
end
Parent.hello
p @@local
Parent.new.world
end
输出结果:
"helloworld"
"helloworld"
"helloworld"
不解释了,看下一个
class Parent
def self.hello
p @@local
end
def world
p @@local = "helloworld"
end
Parent.new.world
Parent.hello
p @@local
end
这个也不解释了,在来下一个
class Parent
def self.hello
p @@local
end
def world
p @@local = "helloworld"
end
Parent.new.world
end
class Child < Parent
p @@local
def self.childone
p @@local
end
def childtwo
p @@local = "helloworld"
end
Child.childone
Child.new.childtwo
end
输出结果:
"helloworld"
"helloworld"
"helloworld"
"helloworld"
这里我想大家也明白了,子类也能全部访问到,因为类变量是作用在父类的类上。当然继承它的子类也受力了,相当于也作用在了子类上,那么子类都能访问到了。
上面我们讲到类变量不要用的原因看下面例子:
class Parent
def self.hello
p @@local
end
def world
p @@local = "helloworld"
end
Parent.new.world
end
class Child < Parent
p @@local = "change paraent @@local"
def self.childone
p @@local
end
def childtwo
p @@local
end
Child.childone
Child.new.childtwo
end
其实我用子类修改了他的类变量值,在实际开发中,子类有可能有很多,如果父类没有修改,子类修改了,我们并不知道哪里修改了。维护起来很麻烦,所以还是好用吧,理解就好。
全局变量:全局变量以 开头,它是全局可见的。Ruby内建的全局变量如 :和$LOAD_PATH表示require读取文件时寻找的目录数组,作用域全局,全局都能访问了。
举个例子:
class Parent
def self.hello
p $local
end
def world
p $local = "helloworld"
end
Parent.new.world
end
class Child
p $local
def self.childone
p $local
end
def childtwo
p $local = "helloworld"
end
Child.childone
Child.new.childtwo
end
输出结果:
"helloworld"
"helloworld"
"helloworld"
"helloworld"
全局变量就不解释了,作用于全局,项目中哪里都能访问到
总结:
局部变量:作用于局部区域,只会在作用域的局部寻找。
实例变量:作用于对象的区域,会在这个对象的作用域内寻找。
类变量:作用于类,类中都能找到,子类继承,相当于作用域子类,子类中也都能找到。
全局变量:作用于全局。