【发布时间】:2017-02-14 09:07:56
【问题描述】:
closures = []
vals = ('a'..'z').to_a
until vals.empty?
val = vals.shift()
closures << lambda { puts val }
end
closures.each { |l| l.call() }
这段 Ruby 代码每次调用都会打印“z”,这有点令人惊讶
def closure(val)
lambda {puts val}
end
closures = []
vals = ('a'..'z').to_a
until vals.empty?
val = vals.shift()
closures << closure(val)
end
closures.each { |l| l.call() }
这会按预期将“a”打印到“z”。
所以我在这里看到的是 Ruby lambda 在创建时捕获其参数的某些不当行为
可以请任何人通过引用 Ruby 规范来解释这种效果吗? (我的 Ruby 是 2.2.5p319/Cygwin)
这是否应该在 Ruby 错误跟踪器中报告为错误?
或者这是预期的行为?
还是已经在其他版本的 Ruby 中修复?
提前感谢您的回复
更新。这是移植到 Perl 的相同代码。令人惊讶的是,但它按预期工作:
use strict;
use warnings;
my @vals = 'a'..'z';
my @subs = ();
while (@vals) {
my $val = shift @vals;
push @subs, sub { print "$val\n"; };
}
$_->() for @subs;
【问题讨论】:
-
出于同样的原因,同样的事情发生在 JavaScript 中,只是
val被评估的时间问题。尝试v = 6; f = -> { puts v }; f.call; v = 11; f.call获取另一个插图。 -
val是一个引用,闭包会记住它们所在的范围,但不会创建它的快照。这将是一个坏主意记忆明智 -
在 Perl 中:` use strict;使用警告;我的@vals = 'a'..'z';我的@subs = (); while (@vals) { 我的 $val = shift @vals;推@subs, sub { print "$val\n"; }; @subs 的 $_->(); ` 按预期从 'a' 打印到 'z'
这怎么解释? -
最终通过使用循环完成了这项工作:`closures = []; vals = ('a'..'z').to_a ;如果 vals.empty,循环会中断吗? ; val = vals.shift() ;闭包
-
太奇怪了:)
标签: ruby lambda closures capture