Ruby 内置的循环结构只有 while 和 until 两种,for ... in ... 基本上可以看作是 Ruby 的语法糖,它最终会发送调用 each 方法的消息给 in ... 后面的对象。这其实也是为了减少模块的耦合而实现的——想要进行迭代的人不需要知道将要迭代的结构,就能实现迭代。所以,通过 Ruby 的鸭子类型,for ... in ... 或者直接调用 each 都不需要保证将要迭代的结构的运行时类型是可迭代的,只要它能响应 each 方法,它就是可以迭代的。所以在目的上 for ... in ... 和 each 没有区别。
这俩唯一的一个区别是局部变量的词法作用域的差异。for ... in ...,包括 while 和 until,都是语法糖,是不会产生新的作用域的,所以循环外部的变量可以在内部引用,而内部创建的局部变量对外也是可见的。each 则不同,由于其循环主体是在 Ruby 的块中,而块是拥有自己的作用域的,所以就有了差别。在块中创建的局部变量对外是不透明的:
[1].each do
i = 2
end
p i # error
复制代码
除非在这个 each 的块的词法范围之外也出现了一个 i = 的赋值语句,这个判定是在词法分析时,一旦被 Ruby 词法分析器看见就知道是局部变量,并不一定要执行: