我希望能够在类中动态“注入(inject)”方法,类似于 Mojolicious 助手发生的情况。像这样的事情:
my $s = SomeThing->new;
$s->helper(do_this => sub {
my $self = shift;
$foo = shift;
});
$s->do_this('bar');
我已经做了一些距离,但我希望注入(inject)的子程序在它们注入(inject)的类的命名空间中运行,而不是在 main
中运行。换句话说,目前的工作原理如下:
$s->do_this('bar');
print 'in main: ', $foo;
这会打印“bar” - 我不希望它如此,而我想要这个
print 'in SomeThing: ', $SomeThing::foo;
改为打印“bar”
虽然这有效,但对我来说似乎很笨拙
$s->helper(do_this => sub {
my $self = shift;
${(ref $self) . '::foo'} = shift;
});
$s->do_this('foo');
print 'in SomeThing: ', $SomeThing::foo; # now this prints "foo"
发生这一切的包看起来像这样:
package SomeThing {
use Mojo::Base -base;
use Carp;
sub helper {
my $self = shift;
my $name = shift || croak "The helper name is required";
my $sub = shift || sub {};
my $namespace = __PACKAGE__;
no strict 'refs';
{
*{"$namespace\::$name"} = $sub
}
}
};
有办法做到这一点吗?我怀疑我会把严格性搞得一团糟——但我还不想放弃(这将是一个值得学习的好技巧)。
最佳答案
您要求更改与已编译的匿名子程序关联的包,以便进行变量查找。不知道可不可以。
即使有可能,这也不是您想要做的事情,因为您的代码仍然无法工作。您必须将 use vars qw( foo );
添加到找到 sub { }
文字的文件中。如果您在 Something.pm
中访问了它,那么除了使用 our $foo;
或 use vars qw( $foo );
之外。
这非常神奇且困惑。通过使用访问器可以轻松避免这种情况。简单替换
$s->helper(
do_this => sub {
my $self = shift;
$foo = shift;
},
);
与
$s->helper(
do_this => sub {
my $self = shift;
$self->foo(shift);
},
);
如果您还需要添加访问器,可以使用以下内容:
$s->helper(
foo => sub {
shift;
state $foo;
$foo = shift if @_;
$foo
},
do_this => sub {
my $self = shift;
$self->foo(shift);
},
);
顺便说一句,来自 Mojo::Util 的 monkey_patch
可以用作 helper
的替代品。 (感谢 @brian d foy 的提出。)它做同样的事情,但它有两个额外的好处:
- 您不需要支持它。
- 它设置 anon sub 的名称,以便堆栈跟踪使用有意义的名称而不是
__ANON__
。
切换到 monkey_patch
并不能解决您的问题,但除了我上面提到的方法的改变之外,我确实建议使用它(或类似的)。
use Mojo::Util qw( );
sub helper { shift; Mojo::Util::monkey_patch(__PACKAGE__, @_); }
关于perl - 我可以在包中注入(inject) perl sub 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59627050/