Ruby的Scope

Scope的描述

  • Scope是范围的意思,在编程中是变量的作用范围。
  • 访问一个变量,或者修改一个变量,首先要进入它的Scope
  • Ruby中有4中普通Scope,和一种闭包Scope
    • 普通Scope分别是
      • Global Scope
      • Class Scope
      • Instance Scope
      • local Scope
    • 闭包Scope专指 Proc对象的Instance Scope,向其它语言中的闭包一样,它会将自由变量存到自己的空间,使得函数的自由变量不被释放

变量的访问规则

  • 每一个表达式被执行,都肯定是在一个Scope里面,这个Scope被称为当前工作空间CWS
    • 最外层的CWS是main
    • 向一个对象发送一个方法,首先是绑定了一个方法,Ruby的方法绑定都是动态绑定;绑定方法的时候初始化一个Local Scope,并设置self为这个对象,也就是receiver的引用。
    • 上面的 Local Scope 里保存的变量是方法内部声明的变量,且不管这个方法迭代调用自己多少次都是相同的Local Scope
    • Local Scope 中可以访问到Global Scope,但如果Local Scope中发生了普通赋值(没有@开头的变量赋值)操作,则直接定义了一个局部变量
    • 如果赋值操作的左值由一个@开头,如@a=1, @符号表示进入 Instance Scope,从而可以修改实例变量
    • 如果赋值操作的左值由两个@开头,如@@a=1,@@符号表示进入 Class Scope,从而修改了类变量,这个类指的是self.class
    • Class Scope 是一个继承链上的类共享的,当然是不包括Class 这个对象的
      	class A
      	def tell_num
      		puts @@num
      		end
      	end
      	class B<A
      	end
      	class C<B
      	end
      	c=C.new
      	class <<c
      	@@num=1
      	end
      	A.new.tell_num
      
    • 上面的例子有一个warning,因为从实例中通过@@num去直接赋值是不被推荐的,正确的做法是类变量只由类来读写

特殊情况

  • 上面提到@@可以进入Class Scope,还有一种比较特别的情况,方法定义 def
    • def 是一个切换Scope的关键字,进入的就是Class Scope之中。Ruby的闭包并不是由函数嵌套来实现的,嵌套函数只是在执行外层函数的时候为类空间新增了一个函数而已,显然由前面提到的Ruby的函数绑定都是动态绑定,类中定义函数就是新增了一个实例方法。而且因为def 进入了类Scope,所以不再可以访问局部变量。
  • 常量
    • 在类中定义一个常量,它会保存在类空间。变量必须用@@声明才会。通过 类名::常量名 可以访问到
  • 方法中不允许再定义类
  • 内部类或者模块是被允许的。类是一种特殊的模块,而模块代表了一个新的NameSpace,所谓名称空间就是一个前缀名称的隐藏
    	class A
    		class B
    		end
    	end
    
    	class C<A
    	end
    	b=C::B.new
    
    	puts b
    	puts b.class
    

规则的例外

  • 私有的setter方法可以被 self显示调用
    • 之所有这个例外,是因为下面两条规则的矛盾
      • 私有方法不能被显式调用
      • 在方法中不显式的方法如果恰好包含了等号结尾,会被认为是一个局部变量的声明
    • 有了上面两个矛盾,导致我们必须将setter的权限放开至protected或public。所以Ruby制定了特殊规则,允许setter方法被self(但不能是self的引用)显式调用
    	class A
    		private
    		def hello=(_nil)
    			puts "hello"
    		end
    		def hi
    			puts "hi"
    		end
    		public
    		def bye
    			begin
    			self.hello=() # will not raise error
    			self.hi # will raise an error
    			rescue NoMethodError =>e
    			puts e
    			end
    
    			begin
    			this=self
    			this.hello=() #will raise an error
    			rescue NoMethodError =>e
    			puts e
    			end
    		end
    	end
    	a=A.new
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值