gpt4 book ai didi

ruby lambda 捕获 : a weird effect and workaround

转载 作者:数据小太阳 更新时间:2023-10-29 08:02:50 26 4
gpt4 key购买 nike

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;

最佳答案

在 Ruby 中,变量是通过引用而不是值来捕获的(在 Python、JavaScript 和许多其他语言中也是如此)。此外, val 的范围是函数范围,而不是循环内部的范围,因此您不会在循环的每次迭代中都获得新变量 val -- 是同一个变量 val;您只是在每次迭代中为其分配另一个值。

在循环的每次迭代中,都会创建一个引用变量 val 的闭包——完全相同的变量 val。因此,当稍后对闭包求值时,它们都读取相同的值——此时(单个)变量 val 的值。

当你将它传递给一个方法并在方法内部创建闭包时,它是不同的,因为闭包捕获的变量是方法体中的 val closure,范围限于该方法。每次调用方法closure,都会得到一个新的变量val,其值为传入的值,此后永远不会改变(closure中没有任何内容) 分配给它)。所以后面这个值被闭包读取的时候,仍然是创建闭包时传递给调用closure的值。

关于 ruby lambda 捕获 : a weird effect and workaround,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39882131/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com