Perl中的新手再次来到这里,尝试理解Perl中的closure
。
所以这是一个我不理解的代码示例:
sub make_saying {
my $salute = shift;
my $newfunc = sub {
my $target = shift;
print "$salute, $target!\n";
};
return $newfunc; # Return a closure
}
$f = make_saying("Howdy"); # Create a closure
$g = make_saying("Greetings"); # Create another closure
# Time passes...
$f->("world");
$g->("earthlings");
所以我的问题是:
$f = \make_saying("Howdy")
吗?我什么时候可以使用&
,因为我尝试使用它来传递参数(&$f("world")
),但它不起作用。world
和earthlings
中的单词如何附加到单词howdy
和greetings
。 注意:我知道$ f在某种程度上与参数howdy
的函数绑定,因此我理解了world
是如何附加的。我不明白的是里面的第二个功能。那个人如何运作它的魔力。对不起,我真的不知道怎么问这个。
答案 0 :(得分:16)
在Perl中,标量变量不能直接保存子程序,它们只能保存引用。这非常类似于标量不能保存数组或哈希,只能包含arrayrefs或hashrefs。
sub { ... }
评估为coderef,因此您可以直接将其分配给标量变量。如果要分配命名函数(例如foo
),则必须获取\&foo
之类的引用。
您可以调用$code->(@args)
或&$code(@args)
等代码参数。
代码
$f = \make_saying("Howdy")
评估make_saying("Howdy")
,并引用返回的值。所以你得到一个指向coderef的引用,而不是coderef本身。
因此,无法像&$f("world")
那样调用它,您需要取消引用一个额外级别:&$$f("world")
。
闭包是绑定到特定环境的函数。
环境由所有当前可见的变量组成,因此闭包始终会记住此范围。在代码中
my $x;
sub foo {
my $y;
return sub { "$x, $y" };
}
foo
是$x
的封闭,因为外部环境由$x
组成。内部子是$x
和$y
上的闭包。
每次执行foo
时,我们都会得到一个新的$y
,因此会有一个新的闭包。每次调用它时,都会返回不同的闭包。
执行make_saying("Howdy")
时,$salute
变量设置为Howdy
。返回的闭包记住了这个范围。
当我们使用make_saying("Greetings")
再次执行时,会再次评估make_saying
的正文。 $salute
现在设置为Greetings
,内部子关闭此变量。此变量与先前存在的$salute
不同,但除了通过第一个闭包之外无法访问。
这两个接待者已经关闭了单独的$salute
个变量。当它们被执行时,它们各自的$salute
仍然在范围内,并且它们可以访问和修改该值。
答案 1 :(得分:4)
如果变量与函数对齐,它是否自动为a 参考那个函数?
没有。在示例中,函数make_saying
返回引用另一个函数。这样的闭包没有名称,可以从其范围之外捕获变量(在示例中为变量$salute
)。
在上面的代码中,我可以写$ f = \ make_saying(“你好”)吗? 我什么时候可以使用&因为我尝试使用它来传递 参数(& $ f(“world”))但它不起作用。
没有。 $f = \make_saying("Howdy")
不是您的想法(详情请参阅 amon 帖子)。您可以编写$f = \&make_saying;
,这意味着“将$ f引用到函数make_saying”。您可以稍后使用它:
my $f = \&make_saying;
my $other_f = $f->("Howdy");
$other_f->("world");
最后,在上面的代码中,他怎么做了世界和 地球人被添加到了喜欢和问候的字样中。
make_saying 创建进入lamda(my $newfunc = sub
)的 my 变量; lambda从 make_saying 返回。它通过“关闭”持有给定单词“你好”(?抱歉不知道用英语表示哪个单词)。
答案 2 :(得分:0)
每次调用子程序'make_saying'时,它: 1a - 创建一个不同的闭包 2a - 将接收到的参数分配给标量'$ salute' 3a - 声明(创建但不执行)内部匿名子例程: 这就是为什么此刻没有任何东西被分配给标量'$ target'也没有执行语句'print'$ salute,$ target!\ n“;' 4a - 最后子程序'make_saying'返回对内部匿名子程序的引用,这个引用成为调用(特定)匿名子程序的唯一方法。
有时你打电话给每个匿名子程序,它: 1b - 将接收到的参数分配给标量'$ target' 2b - 另请参阅标量'$ salute',它将在创建匿名子例程的时刻分配值(当被称为父子例程'make_saying'时 3b - 最后执行语句'print'$ salute,$ target!\ n“;'