这里又是一个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");
所以我的问题是:
1.如果一个变量被赋值给一个函数,它是否自动成为对该函数的引用?
1.在上面的代码中,我可以写$f = \make_saying("Howdy")
吗?什么时候可以使用&
,因为我在传递参数(&$f("world")
)时尝试使用它,但它不起作用。
1.最后,在上面代码中,字符串world
和earthlings
是如何附加到字符串Howdy
和Greetings
上的。
注意:我知道$f在某种程度上绑定到了带参数"Howdy"
的函数,所以这就是我对"world"
是如何被附加的理解。我不明白的是里面的第二个函数。它是如何操作它的魔力的。抱歉,我真的不知道如何问这个。
3条答案
按热度按时间e4yzc0pl1#
在Perl中,标量变量不能直接保存子例程,它们只能保存引用。这很像标量不能保存数组或散列,只能保存arrayref或hashref。
sub { ... }
的值是一个coderef,所以你可以直接把它赋值给一个标量变量。如果你想赋值给一个命名函数(例如foo
),你必须获得像\&foo
这样的引用。您可以呼叫类似
$code->(@args)
或&$code(@args)
的程式码指涉。该代码
计算
make_saying("Howdy")
,并获取对返回值的引用。因此,您获得的引用指向coderef,而不是coderef本身。因此,不能像
&$f("world")
那样调用它,需要解引用一个额外的级别:&$$f("world")
.闭包是绑定到特定环境的函数。
环境由所有当前可见的变量组成,因此闭包总是记住该作用域。
foo
是$x
上的闭包,因为外部环境由$x
组成。内部子是$x
和$y
上的闭包。每次执行
foo
时,我们都会得到一个新的$y
,从而得到一个新的闭包。最重要的是,当foo
离开时,$y
不会“超出作用域”,但它会“保持活动”,因为它仍然可以从返回的闭包访问。简而言之:$y
是返回的闭包的“本地状态”。当我们执行
make_saying("Howdy")
时,变量$salute
被设置为Howdy
,返回的闭包会记住这个作用域。当我们用
make_saying("Greetings")
再次执行它时,make_saying
的主体被再次求值。$salute
现在被设置为Greetings
,并且内部子函数在这个变量上结束。这个变量与之前的$salute
是分开的,后者仍然存在,但只有通过第一个闭包才能访问。两个greeter已经关闭了单独的
$salute
变量。当它们被执行时,它们各自的$salute
仍然在作用域中,并且它们可以访问和修改值。d4so4syb2#
如果一个变量被赋值给一个函数,它是否自动成为对该函数的引用?
不可以。在示例中,函数
make_saying
返回引用了另一个函数。这种闭包没有名称,可以捕获作用域之外的变量(示例中的变量$salute
)。在上面的代码中,我可以写$f = \make_saying(“Howdy”)吗?什么时候可以使用&,因为我在传递参数(&$f(“world”))时尝试过使用它,但它不起作用。
不,
$f = \make_saying("Howdy")
不是你想的那样(阅读amonpost了解详情)。你可以写$f = \&make_saying;
,意思是“放入$f对函数make_saying的引用”。你以后可以这样使用它:最后,在上面的代码中,单词world和earthlings是如何附加到单词howdy和greatings上的。
make_saying创建my变量,该变量进入lambda(
my $newfunc = sub
);这个lambda是从make_saying返回的。它保存了从“关闭”到“你好”的给定单词(抱歉,不知道英语中的哪个单词)。ego6inou3#
每次调用子例程“make_saying”时,它:
1.创建一个不同的闭包
1.将接收到的参数赋给标量“$alquet”
1.定义(创建但不执行)内部匿名子例程:这就是为什么在那个时刻没有给标量
$target
赋值,也没有执行语句print "$salute, $target!\n";
的原因。1.最后,子例程“make_saying”返回对内部匿名子例程的引用,该引用成为调用(特定的)匿名子例程的唯一方式。
每次调用每个匿名子例程时,它:
1.将接收到的参数分配给标量
$target
1.还可以看到标量
$salute
,该标量将具有在创建匿名子例程时(调用其父子例程make_saying
时)分配的值1.最后执行语句
print "$salute, $target!\n";