Mark24
笔记:Ruby控制作用域相关实验
导航关联
默认的情况
Class、Module、def 分别产生作用域门,他们自己的变量仅仅对自己可见。 符合预期。
class A
ka_a = 'ka a'
ka_b = 'ka b'
puts '--Class A'
pp local_variables
module B
mb_a = 'module b var a'
puts '--Class B'
pp local_variables
end
def c
puts '--method c'
pp local_variables
end
end
A.new.c
# --Class A
# [:ka_a, :ka_b]
# --Class B
# [:mb_a]
# --method c
# []
块和扁平作用域
我们只要把例子简单的修改定义 def的部分换成块模式定义:
top_a = "top_a"
top_b = "top_b"
class A
ka_a = "ka a"
ka_b = "ka b"
puts "--Class A"
pp local_variables
module B
mb_a = "module b var a"
puts "--Class B"
pp local_variables
end
define_method :c do
puts "--method c"
pp local_variables
end
end
A.new.c
puts "--top-level--"
pp local_variables
# output >>>>>
# --Class A
# [:ka_a, :ka_b]
# --Class B
# [:mb_a]
# --method c
# [:ka_a, :ka_b]
# --top-level--
# [:top_a, :top_b]
块实际上是函数+所在环境的绑定(也叫做闭包)。
参考《Ruby原理剖析》,实际上在Ruby内部块是一个结构体,保存了 所在环境的EP(环境指针Environment Pointer),那么在解析变量的时候,可以看到外面一层。
这个实验中,c实例看不到 top level(最外层称为 top level)足够说明问题,块只能绑定他所在的这一层作作用域。
块的这种能力在《Ruby元编程》里称为 打破作用域门(Scope Gate)。也叫扁平作用域,看起来就像 块和外部的作用域压平在一起了。
嵌套块 传递作用域
还是把刚才的例子简单变化一下,A类用 Class.new 和块的方式生存。这时候 A和c是嵌套的。
A 携带了环境绑定,c 也绑定到了所定义的A里。作用域可见性实现了一种传递。
词法作⽤域: 词法作⽤域就是指作⽤域是由代码中函数声明的位置来决定的,所以词法作⽤域是静态的作 ⽤域,通过它就能够预测代码在执⾏过程中如何查找标识符。
这个方式可以理解为词法作用域,块的作用域就是代码位置所在之处的作用域。
在执行的底层,块的结构体中 EP指针,指向的是当前执行栈栈帧。结果是一样的。(词法和栈帧的结果一致性的判断我不知道对不对。结果上来看是这样。)
top_a = "top_a"
top_b = "top_b"
A = Class.new do
ka_a = "ka a"
ka_b = "ka b"
puts "--Class A"
pp local_variables
module B
mb_a = "module b var a"
puts "--Class B"
pp local_variables
end
define_method :c do
puts "--method c"
pp local_variables
end
end
A.new.c
puts "--top-level--"
pp local_variables
共享作用域
这段例子展示的是 一个def 里面有两个 块在一个作用域内部,他们之间可以共享变量,从结果上可以看出来。
而且,由于最外层 def的存在,建立了一个作用域门,这意味着外面也无法访问内部。
所以这里起到了一个效果就是两个块在一个私有空间里共享作用域。
def counter_job
shared_counter = 0
define_method :inc do
shared_counter += 1
end
define_method :display do
puts "[Result]: #{shared_counter}"
end
Kernel.send :inc
Kernel.send :inc
Kernel.send :inc
Kernel.send :display
puts "--in counter_job"
pp local_variables
end
counter_job
puts "--top level--"
pp local_variables
# output >>>>>>
# [Result]: 3
# --in counter_job
# [:shared_counter]
# --top level--
# []
总结
我们知道了 块可以扁平作用域、嵌套的块可以传递作用域、作用域门内部两个块可以共享作用域。顺着这个思路,我们可以通过写法控制代码的作用域了。