Ruby 的变量(作用域)

6 篇文章 0 订阅

在讲解变量之前首先我们要明白什么是作用域?

简单的理解就是作用域是寄居在一定的区域类,相当于一个寄居场所。

先举个例子:

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"

全局变量就不解释了,作用于全局,项目中哪里都能访问到

总结:

局部变量:作用于局部区域,只会在作用域的局部寻找。
实例变量:作用于对象的区域,会在这个对象的作用域内寻找。
类变量:作用于类,类中都能找到,子类继承,相当于作用域子类,子类中也都能找到。
全局变量:作用于全局。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值