我很困惑块内变量的范围。这工作:范围令人困惑
f = 'new'
[1,2,3].each do |n| puts f * n end
#=> new newnew newnewnew
但这并不:
[1,2,3].each do |n|
a ||=[]
a << n
end
a
#=>a does not exsit!
这是为什么?请为我提供一些关于这个话题的资源。
我很困惑块内变量的范围。这工作:范围令人困惑
f = 'new'
[1,2,3].each do |n| puts f * n end
#=> new newnew newnewnew
但这并不:
[1,2,3].each do |n|
a ||=[]
a << n
end
a
#=>a does not exsit!
这是为什么?请为我提供一些关于这个话题的资源。
什么让人困惑?
在第一片断f
被创建并随后each
块被执行,它可以看到外面本身的东西(称为封闭的范围)。所以它可以看到f
。
在第二个片段中,您在该块内部创建了a
,因此其范围就是该块。在块之外,a
不存在。
当你引用一个名字时(例如a
),ruby将从当前作用域向外移动,查看所有封闭作用域的名称。如果它在其中一个封闭范围内找到它,它将使用与该名称关联的值。如果不是,则返回大多数本地范围并在那里创建名称。随后的名称查找将产生与该名称关联的值。
块结束时,该范围内的名称将丢失(值不会丢失,只是名称;当垃圾回收器发现没有更多名称(或任何内容)引用时,值会丢失该值,并且gc收集该值以重用其内存)。
当一个模块结束时,您将踏上一个台阶。由于您在下面的步骤中看不到任何名称,因此您之前步骤中的所有名称都会丢失。
如果这可以帮助你,那么想一想。如果没有,不要。
其实你在第二个步骤,因为你在全球范围内不是,但是从全球范围内使用的名称,你必须在名称的开头使用$。因此,在楼梯示例中,如果您要查找的名称在开头处具有$,则可直接查看最上面的步骤。如果没有,你看起来不那么远。然而,这是错误的,因为程序中的所有楼梯都会共享相同的顶级步骤,这是很奇怪的想法。
+1。这取决于范围'a'是***第一***使用。 – 2011-06-12 17:32:42
如果我使用比喻,我会提到一辆带烟熏玻璃的汽车;你可以从内部看到外部,但不是相反。 – sawa 2011-06-12 17:57:15
@sawa是的,但你有嵌套的范围,这将像汽车内的汽车。然后事情开始变得混乱。 – 2011-06-12 17:58:00
很简单,一个块中定义的变量是不可见的外(如果发生这种情况,我们会说变量已经泄露,并作为顾名思义,这将是坏的):
>> lambda { x = 1 }.call
=> 1
>> x
NameError: undefined local variable or method `x' for main:Object
地图的效果要好得多:
a = [1,2,3].map do |n|
n
end
不需要声明a
外块。
你是对的!但我只想举例说明我不能在范围之外使用的变量 – mko 2011-06-14 09:45:28
@sawa感谢您再次纠正我的问题 – mko 2011-06-14 09:19:05