Perl 如何通过 subroutine reference 创建 lexical sub?
可以。先用 my sub foo; 声明词法子程序,再通过 \&foo = $ref; 将它绑定到已有的 subroutine reference。声明和绑定需要分开写,不能使用问题中的 my \&foo = ...。
正确写法
下面的示例适用于 Perl 5.26 及更高版本:
use v5.26;
use strict;
use warnings;
{
use feature 'refaliasing';
no warnings 'experimental::refaliasing';
my $ref = sub {
my ($a, $b) = @_;
return $a + $b;
};
my sub foo;
\&foo = $ref;
print foo(2, 3), "\n";
}
声明和绑定完成后,就可以用 foo(2, 3) 调用 $ref 引用的子程序。refaliasing 支持对 \&sub 赋值,Perl 的实现也处理了词法子程序的绑定。参见 perlref 的引用赋值说明和 Perl 5.26 的相关实现。
如果不需要保留 $ref 变量,也可以直接写:
my sub foo;
\&foo = sub { ... };
这两行代码同样需要放在启用 refaliasing 的作用域内。
为什么原来的声明不成立?
declared_refs 允许使用 my \$x、my \@array 等引用声明语法,但 my \&foo 不是合法的词法子程序声明。词法子程序需要先用 my sub foo; 声明,再执行引用赋值。
这个方案只需要 refaliasing,不需要 declared_refs。两种功能的用途可参见 perlref 的引用声明说明。
作用域和使用限制
foo 这个词法名称只在声明之后、所在词法作用域内可见。离开代码块后,无法再通过这个词法绑定调用它;如果外部有同名的 package sub,外部的 foo() 可能解析到那个子程序。Perl 5.26 起,lexical sub 不再是实验功能,也无需显式启用 lexical_subs。参见 perlsub 的 Lexical Subroutines 说明。
绑定右侧必须是有效的 CODE reference,而且要先执行绑定,再调用 foo()。refaliasing 仍是实验功能,关闭对应警告只会隐藏提示。官方文档还列出了它与闭包配合使用时的限制,尤其不要假定在内层子程序或 eval 中重新绑定外层词法名称,会同步改变外层的绑定。参见 refaliasing 的限制说明。
如果只想在局部范围内保存并调用一个回调,使用普通词法变量即可,无需启用实验功能:
my $foo = sub {
my ($a, $b) = @_;
return $a + $b;
};
print $foo->(2, 3), "\n";
这种方式使用 $foo->(...) 调用,不会创建可通过 foo(...) 调用的词法子程序名称。
备注:内容仅供参考。
