从字符串生成子例程引用

时间:2015-05-14 11:54:25

标签: perl

我正在创建一个调度表:

  my $dispatch = { 
    'do_this' => \&do_this,
    'do_that' => \&do_that,
    'do_something' => \&do_something,
    'do_something_else' => \&do_something_else,
  };

我没有为密钥和值键入相同的字符串,而是希望这样做:

my $dispatch_values = ['do_this', 'do_that', 'do_something', 'do_something_else'];
my $dispatch = generate_dispatch_table($dispatch_values);

sub generate_dispatch_table {
  my $values = shift;
  my $table = {};
  foreach $value (@$values) {
    $table{$value} = #WHAT GOES HERE?
  }
  return $table;  
}

但我不知道如何从字符串生成子例程引用。

2 个答案:

答案 0 :(得分:4)

只需使用\&{ $sub_name }

#! /usr/bin/perl
use warnings;
use strict;

sub hi  { print "Hi\n"  }
sub bye { print "Bye\n" }

my %dispatch = map { $_, \&{$_} } qw(hi bye);

chomp(my $action = <>);
$dispatch{$action}->();

答案 1 :(得分:1)

替代方案包括:

  • 使用对象。
  • 使用包裹。

对于一个对象,它几乎就是你习惯的对象:

#! /usr/bin/perl

package Foo;
use warnings;
use strict;

sub hi  { print "Hi\n"  }
sub bye { print "Bye\n" }

sub new { bless {} }

package main;

my $dispatcher = Foo->new;
chomp(my $action = <>);
$dispatcher->$action();

当然,应该检查你是否can做了这个动作,但我们在这里省略了一些基本的检查。

另一个好的检查是不按原样使用操作,但是如果对象中有其他非分派方法,则使用指示它可分派的前缀:

#! /usr/bin/perl

package Foo;
use warnings;
use strict;

sub do_hi  { print "Hi\n"  }
sub do_bye { print "Bye\n" }

sub new { bless {} }

package main;

my $dispatcher = Foo->new;
chomp(my $action = <>);
$action = "do_" . $action;
$dispatcher->$action();

唯一的区别是do_前缀,但现在调用者无法通过调度程序调用{​​{1}}。否则,它是相同的 - 这个调度员将发送newhi像choroba的答案。

当然,请记住,如果您传入参数,bye是第一个参数。

通过包这样做几乎是一样的:

$self

这里,第一个参数当然是“Foo”。我们也不需要对象,因此不需要构造函数。

但是,您可以将其直接应用到原始问题中,并避免使用其他一些标记。只需删除包声明,即使在默认(主)包中也可以将#! /usr/bin/perl package Foo; use warnings; use strict; sub do_hi { print "Hi\n" } sub do_bye { print "Bye\n" } package main; chomp(my $action = <>); $action = 'do_' . $action; Foo->$action(); 更改为Foo->$action()。但是,如果您不希望传递包名,我们只需更进一步:

__PACKAGE__->$action()

TMTOWTDI。选择对您和您的代码布局最有意义的那个。有时候我使用对象模型,有时候是另一个。