让我们通过一个例子来说明这一点:
results = []
(1..3).each do |i|
results << lambda { i }
end
p results.map(&:call)
很棒,这正是预期的结果。现在请检查以下内容:
results = []
for i in 1..3
results << lambda { i }
end
p results.map(&:call)
哎呀,怎么回事?相信我,这种类型的错误很难追踪。Python或JS开发人员应该知道我在说什么 :)
仅仅因为这个原因,我就像瘟疫一样避免使用这些循环,虽然还有更多支持这个立场的好论点。正如Ben正确指出的那样,使用Enumerable
中的适当方法几乎总是比使用老式的命令式for
循环或更炫的Enumerable#each
更好。例如,上面的示例也可以简洁地写成
lambdas = 1.upto(3).map { |i| lambda { i } }
p lambdas.map(&:call)
我扩展了问题:在 Ruby 中,除了 for ... do ... end 之外,我们是否还能看到类似的出现 do/end 块定界符,但实际上内部没有作用域?还有其他什么吗?
每一个循环结构都可以这样使用:
while true do
end
until false do
end
另一方面,我们可以在不使用 do
的情况下编写这些代码(这显然更可取):
for i in 1..3
end
while true
end
until false
end
再扩展一下这个问题,有没有一种用花括号 { block } 来编写 for 循环的方法?
没有。同时需要注意,在 Ruby 中术语“block”有特殊的含义。
for
的问题不仅在于它与使用do/end
的其他结构有微妙的差异,而且它只能用于一个原因:遍历可枚举对象。通常,来自函数式编程的结构,如select
或map
,比起从 C 直接继承的普通循环更适合表达问题。 - Niklas B.for
循环,我们再给您提供更好的替代方案? :) 否则我认为这个问题只是 https://dev59.com/aXA75IYBdhLWcg3wdIl0 的重复。 - Niklas B.