如何得知使用哪个别名来调用别名子例程? caller
给出了原始的sub
名称,但我想查看呼叫时使用的名称。
示例:
use 5.010;
sub x_y_z {
return ( caller(0) )[3];
}
*foo_bar_baz = \&x_y_z;
say x_y_z(); # x_y_z
say foo_bar_baz(); # x_y_z, but need foo_bar_baz
编辑以解决XY问题
我添加了另一个示例来展示我的更深层次的意图。我想创建调度表来路由一些任务:
my $dispatch = {
x => {
y => {
z => sub {
&x_y_z;
},
}
},
a => {
b => {
c => {
d => sub {
&a_b_c_d;
},
}
}
}
}
sub foo {
my @arg = ( split '_', ( split( '::', ( caller(0) )[3] ) )[1] );
return @arg;
}
*x_y_z = \&foo;
*a_b_c_d = \&foo;
您可能会想到,这棵树可能长得很大。现在,调度树中的许多叶子需要基本相同的子对象,它们的命名方式不同(它们的命名方式不同),我希望只包含一个子对象,并为特定任务添加别名。
答案 0 :(得分:4)
不能。 foo_bar_baz
是别名。 caller
报告所声明的子例程的名称,而不是调用该子例程的名称。请注意,并非所有子例程都具有名称,并且并非所有调用都按名称。 (匿名子仅作为CODE
引用存在;它们在符号表中没有条目。任何命名或未命名的子都可以通过引用来调用。)
也就是说,这里不需要别名。您真正想要的是子程序应该在其上运行的数据库,表等的额外参数。惯用的方法是包装通用子并通过包装传递该信息:
my %dispatch = (
a => { b => { c => sub { foo('a', 'b', 'c', @_) } } },
x => { y => { z => sub { foo('x', 'y', 'z', @_) } } },
);
$dispatch{a}{b}{c}->('foo');
$dispatch{x}{y}{z}->('bar');
sub foo {
my $db = shift;
my $table = shift;
my $task = shift;
my @params = @_;
say "$db $table $task: @params";
}
答案 1 :(得分:4)
您试图做的事在Perl的数据模型中根本不可能实现。别名只是别名,不是具有自己标识的对象。
请注意,可以复制子例程并为其重新命名,例如:
use Sub::Name;
*x_y_z = subname x_y_z => \&foo;
但是您将必须手动执行此操作。
除了堆栈跟踪以外,不要依赖任何子名称。试图在这些名称之上构建任何逻辑都可能会导致难以调试的混乱,而不是优雅的软件。
最好将路由名作为显式参数传递给处理程序函数,并创建一个辅助函数以对必要的管道进行抽象。例如:
my %routes;
sub route {
my ($name, $handler) = @_;
$routes{$name} = sub { $handler->($name => @_) };
return;
}
sub common_handler { ... }
route a_b_c => \&common_handler;
route x_y_z => \&common_handler;
route foo_bar => sub {
my ($route) = @_;
say "Custom handler invoked for route $route";
};
$routes{$name}->(@args);
如果绝对必要,您当然可以实现这样的route
函数,以便它将处理程序作为命名子例程安装。但是到那时,您正在构建某种类似于Moo(se)的框架,而不是普通的Perl模块。