如何在 Perl 中调用存储在哈希中的函数名称?
我确信这在文档中的某个地方有所涉及,但我一直找不到它...我正在寻找语法糖,它可以调用名称存储在哈希中的类上的方法(而不是简单的标量):
use strict; use warnings;
package Foo;
sub foo { print "in foo()\n" }
package main;
my %hash = (func => 'foo');
Foo->$hash{func};
如果我首先将 $hash{func}
复制到标量变量中,那么我可以调用 Foo->$func
就好了。 . 但是缺少什么才能使 Foo->$hash{func} 正常工作呢?
(编辑:我并不是想通过调用类 Foo
上的方法来做任何特别的事情——这可以很容易地成为一个受祝福的对象(在我的实际代码中它是);它只是使用类方法更容易编写一个独立的示例。)
编辑2:为了完整性,下面的注释,这就是我实际上正在做的事情(这是在 Moose 属性糖库中,使用 Moose::Exporter):
# adds an accessor to a sibling module
sub foreignTable
{
my ($meta, $table, %args) = @_;
my $class = 'MyApp::Dir1::Dir2::' . $table;
my $dbAccessor = lcfirst $table;
eval "require $class" or do { die "Can't load $class: $@" };
$meta->add_attribute(
$table,
is => 'ro',
isa => $class,
init_arg => undef, # don't allow in constructor
lazy => 1,
predicate => 'has_' . $table,
default => sub {
my $this = shift;
$this->debug("in builder for $class");
### here's the line that uses a hash value as the method name
my @args = ($args{primaryKey} => $this->${\$args{primaryKey}});
push @args, ( _dbObject => $this->_dbObject->$dbAccessor )
if $args{fkRelationshipExists};
$this->debug("passing these values to $class -> new: @args");
$class->new(@args);
},
);
}
我已将上面标记的行替换为:
my $pk_accessor = $this->meta->find_attribute_by_name($args{primaryKey})->get_read_method_ref;
my @args = ($args{primaryKey} => $this->$pk_accessor);
PS。我刚刚注意到,同样的技术(使用 Moose 元类来查找 coderef 而不是假设其命名约定)不能也可用于谓词,如 Class::MOP::Attribute 没有类似的 get_predicate_method_ref
访问器。 :(
I'm sure this is covered in the documentation somewhere but I have been unable to find it... I'm looking for the syntactic sugar that will make it possible to call a method on a class whose name is stored in a hash (as opposed to a simple scalar):
use strict; use warnings;
package Foo;
sub foo { print "in foo()\n" }
package main;
my %hash = (func => 'foo');
Foo->$hash{func};
If I copy $hash{func}
into a scalar variable first, then I can call Foo->$func
just fine... but what is missing to enable Foo->$hash{func}
to work?
(EDIT: I don't mean to do anything special by calling a method on class Foo
-- this could just as easily be a blessed object (and in my actual code it is); it was just easier to write up a self-contained example using a class method.)
EDIT 2: Just for completeness re the comments below, this is what I'm actually doing (this is in a library of Moose attribute sugar, created with Moose::Exporter):
# adds an accessor to a sibling module
sub foreignTable
{
my ($meta, $table, %args) = @_;
my $class = 'MyApp::Dir1::Dir2::' . $table;
my $dbAccessor = lcfirst $table;
eval "require $class" or do { die "Can't load $class: $@" };
$meta->add_attribute(
$table,
is => 'ro',
isa => $class,
init_arg => undef, # don't allow in constructor
lazy => 1,
predicate => 'has_' . $table,
default => sub {
my $this = shift;
$this->debug("in builder for $class");
### here's the line that uses a hash value as the method name
my @args = ($args{primaryKey} => $this->${\$args{primaryKey}});
push @args, ( _dbObject => $this->_dbObject->$dbAccessor )
if $args{fkRelationshipExists};
$this->debug("passing these values to $class -> new: @args");
$class->new(@args);
},
);
}
I've replaced the marked line above with this:
my $pk_accessor = $this->meta->find_attribute_by_name($args{primaryKey})->get_read_method_ref;
my @args = ($args{primaryKey} => $this->$pk_accessor);
PS. I've just noticed that this same technique (using the Moose meta class to look up the coderef rather than assuming its naming convention) cannot also be used for predicates, as Class::MOP::Attribute does not have a similar get_predicate_method_ref
accessor. :(
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
但为了清楚起见,我可能仍将其写为:
But for clarity, I'd probably still write it as:
您存储子例程名称而不是代码引用是否有原因?
例如,
您不会传递类名,但如果这对您很重要,您可以使用类似的东西
Is there a reason you are storing subroutine names instead of the references to code?
e.g.
You won't be passing the class name, but if that's important to you, you can use something like
您是否尝试过UNIVERSALcan方法?你应该能够实现这样的东西:
我做了一个无用的单行示例来演示:
Have you tried UNIVERSAL's can method? You should be able to implement something like this:
I made a useless, one-line example to demonstrate: