范围令人困惑

mko*_*mko 0 ruby

我对块内变量的范围感到困惑.这有效:

f = 'new'
[1,2,3].each do |n| puts f * n end
#=> new newnew newnewnew
Run Code Online (Sandbox Code Playgroud)

但这不是:

[1,2,3].each do |n|
  a ||=[]
  a << n
end
a
#=>a does not exsit!
Run Code Online (Sandbox Code Playgroud)

为什么是这样?请为我提供一些关于这个主题的资源.

Set*_*gie 7

什么令人困惑?

在第一个片段f中创建然后each执行块,它可以看到自身之外的东西(称为封闭范围).所以它可以看到f.

a块中创建的第二个片段中,其范围就是该块.在街区外,a不存在.

当您引用名称(a例如)时,ruby将从当前范围向外,查看名称的所有封闭范围.如果它在其中一个封闭范围内找到它,则使用与该名称关联的值.如果没有,它将返回到最本地范围并在那里创建名称.后续的名称查找将产生与该名称关联的值.

当块结束时,该范围内的名称将丢失(不会丢失,只会丢失名称;当垃圾收集器看到没有更多名称(或任何内容)引用该值时,值将丢失,并且gc收集值以重用其内存).


如果可视化是您的事情,我发现将范围视为一个阶梯是有帮助的,并且在程序开始时,您站在最前面的步骤1.每次输入一个块时,您都会退一步.您可以看到当前步骤中的所有内容,以及您所在位置上方的所有步骤,但以下步骤中没有任何内容.当您引用变量名称时,可以查看您正在查找的步骤.当你看到它时,你使用那个值.如果你没有看到它,你会看到你正在进行的下一步.如果你看到它,你就使用那个值.你一遍又一遍地这样做,直到你看到最顶端的一步,但没有看到这个名字.如果发生这种情况,您可以在您所站立的步骤上创建名称(如果您正在查找作业,则为其指定一个值).下次您查找该名称时,您将在您站立的步骤中看到它,并在那里使用它.

当一个街区结束时,你会爬上一个楼梯台阶.由于您在下面的步骤中看不到任何名称,因此您之前执行的步骤上的所有名称都将丢失.

如果这对你有所帮助,那就这么想吧.如果没有,不要.

1 实际上你是第二步,因为你不在全球范围内,但要使用全局范围的名称,你必须在名称的开头使用$.所以在楼梯示例中,如果您要查找的名称在开头有一个$,则直接查看顶部步骤.如果没有,你看起来不那么远.然而,这有点不对,因为程序中的所有楼梯都会分享相同的顶级步骤,这是一个奇怪的想法.

  • 它就像一套俄罗斯娃娃,每个都用烟熏玻璃制成,娃娃和礼品盒之间有全局变量.事实上,它是如何在解释器中实际实现的. (3认同)