如何在不禁用严格的“引用”的情况下重命名 perl __ANON__ sub?

Ste*_*e O 5 perl reference strict anonymous-function symbol-table

我在这里找到了在 Perl 中重命名匿名订阅者的解决方案。它涉及临时修改符号表以插入所需的名称。此解决方案使用要替换的硬编码符号表名称。我的问题是我想在运行时动态选择符号表名称。像这样的东西:

   $pkg = 'MyPkg::ModA::';
   $name = 'subname';
   ...
   no strict 'refs';
   local *{"${pkg}__ANON__"} = "$name [anon]";
   strict refs;
Run Code Online (Sandbox Code Playgroud)

使其工作的唯一方法是禁用严格引用。如果它们未被禁用,脚本将失败并显示以下消息:

不能使用字符串 ("MyPkg::ModA::__ANON__") 作为符号引用,而在 /path/to/source/File.pm 行 xx 处使用“严格引用”

请注意,可以使用等效语句

   local ${$pkg}{__ANON__} = "$name [anon]";
Run Code Online (Sandbox Code Playgroud)

带有类似的错误消息:

不能使用字符串 ("MyPkg::ModA::") 作为 HASH 引用,而在 /path/to/source/File.pm 行 xx 处使用“严格引用”

是否可以在不禁用严格引用的情况下做同样的事情?

TMI/DNR:
如果您感兴趣,这里有一个完整的示例。具有讽刺意味的是,我的解决方案使用匿名子重命名给定的匿名子。

ModA.pm

package MyPkg::ModA;

use strict;
use warnings;
use MyPkg::Util;

# Create a new instance.
sub new
{
   my ($type, $class, $self);

   # allow for both ModA::new and $moda->new
   $type = shift;
   $class = ref $type || $type;
   $self = {@_};
   bless $self, $class;

   # use exported Util::anon sub here
   $self->{func} = anon sub
   {
      my ($arg);

      $arg = shift;

      debug "\$arg: $arg";
   };

   return $self;

} # new

1;
__END__
Run Code Online (Sandbox Code Playgroud)

ModB.pm

package MyPkg::ModB;

use strict;
use warnings;
use MyPkg::ModA;

# Create a new instance.
sub new
{
   my ($type, $class, $self);

   # allow for both ModB::new and $modb->new
   $type = shift;
   $class = ref $type || $type;
   $self = {@_};
   bless $self, $class;

   $self->{modA} = MyPkg::ModA->new;

   return $self;

} # new

# Do something with ModA.
sub doit
{
   my ($self);

   $self = shift;

   $self->{modA}->{func}->('What is your quest?');

} # doit

1;
__END__
Run Code Online (Sandbox Code Playgroud)

实用程序

package MyPkg::Util;

use strict;
use warnings;
require Exporter;

our (@ISA, @EXPORT);

@ISA = qw(Exporter);
@EXPORT = qw(
   anon
   debug);

# Temporarily mangle symbol table to replace '__ANON__'.
sub anon
{
   my ($func, $sub, $pkg, $name);

   $func = shift;

   $sub = (caller 1)[3];
   $sub =~ /(.*::)(.+)/;
   $pkg = $1;
   $name = $2;

   return sub
   {
      # TODO How to do this w/o disabling strict?
      #no strict 'refs';
      # temp symbol table mangling here
      # ${$pkg}{__ANON__} is equivalent to *{"${pkg}__ANON__"}
      local *{"${pkg}__ANON__"} = "$name [anon]";
      use strict;
      $func->(@_);
   };

} # anon

# Print a debug message. 
sub debug
{
   my($fname, $line, $sub);

   ($fname, $line) = (caller 0)[1,2];
   $fname =~ s/.+\///;

   $sub = (caller 1)[3] || 'main';
   $sub =~ s/.*::(.+)/$1/;

   printf STDERR "%-10s %s(%s) - \"%s\"\n", $fname, $sub, $line, "@_";

} # debug

1;
__END__
Run Code Online (Sandbox Code Playgroud)

mytest.pl

#! /usr/bin/perl

use strict;
use warnings;
use MyPkg::ModB;

# Stuff happens here.
my ($modB);

$modB = MyPkg::ModB->new;
$modB->doit;
Run Code Online (Sandbox Code Playgroud)

ike*_*ami 6

您可以使用核心模块Sub::Utilset_subname.

use Sub::Util qw( set_subname );

sub anon {
   ...
   return set_subname("$name [anon]", $func);
 }
Run Code Online (Sandbox Code Playgroud)