将值绑定到Perl中的函数

时间:2009-12-12 02:17:11

标签: perl

我正在使用类似于以下内容的哈希表来存储可以在提示符处输入的字母以及该选项的描述和将被调用的函数。

my %main_menu = (
    "l" => ["list locks", \&list_locks],
    "n" => ["new lock", \&new_lock],
    "u" => ["update lock", \&update_lock]
    );

menu_prompt(\%main_menu)生成以下菜单:

 ________________________ 
| l - list locks         |
| n - new lock           |
| u - update lock        |
|________________________|
(l,n,u)> 

当用户输入“u”时,在提示符下将调用update_lock函数。

现在,我想生成一个带有新哈希表(%lock_menu)的类似菜单。但是,我将首先提示用户输入他们想要更新的锁的ID。

Please enter the ID of a lock to update: 1

You are updating lock 1.
 __________________ 
| l - list users   |
| n - new user     |
|__________________|
(p,u,c)> 

我想存储锁ID,以便锁定菜单功能可以访问它。例如:

my %users_menu = (
 "l" => ["list users", \&list_users],
 "n" => ["new user", \&new_user]);

我无法弄清楚如何将锁ID附加到%users_menu中的函数。因此,当选择“l”时,将使用该数字作为第一个参数调用list_users。

我似乎记得ML,如果你在ML语言中调用一个只有一个参数的n参数函数,它将生成一个带有n-1个参数的函数。因此,例如,将func(int,int,int)作为func(5)调用将产生func(int,int),第一个参数保存为5。

这在Perl中是否可行?或者我是以错误的方式来做这件事的?请告诉我。

UPDATE:这是打印菜单(print_options)的功能,提示用户输入一个字母,并调用相应的功能。

sub menu_prompt
{
    my $options = shift;

    print_options $options;

    my $choice = <>;
    chomp $choice;

    if (defined $$options{$choice})
    {
        $$options{$choice}[1](); # no arguments
    }
}

我想找到一种方法将这个函数用于所有菜单,而不是编写一个单独的函数,其中值被传递给函数。

4 个答案:

答案 0 :(得分:6)

没有发布更多示例代码很难给出完整的答案,但是当你从散列中调用你的sub时,为什么不把它传递给锁定值呢?

my $num = ... # get lock number;

$users_menu{"n"}[1]->($num)

# calls "new_user" passing it $num

编辑问题:

sub menu_prompt {
    my $options = shift;

    print_options $options;

    my $choice = <>; # i assume the diamond operator got stripped
    chomp $choice;   # second my is in error

    if (defined $$options{$choice}) {
        return $$options{$choice}[1](@_); 
             # any additional arguments to menu_prompt will be passed to the sub
             # return the value for future processing
    }
}

答案 1 :(得分:6)

你想要咖喱功能。

有许多CPAN模块(见帖子末尾)用于currying。这是关闭咖喱的一个例子。

sub curry {
    my $f = shift;
    my $a = shift;
    sub { $f->( $a, @_ ); }
}


my ($input, $func);
$input = 2;
$func  = curry( sub { print join "\n", @_ }, $input );

$input = 12;
$func  = curry( $func , $input );

$input = 99;

$func->(4,6,8,10,19);


#outputs
2
12
4
6
8
10
19

另请参阅Data::UtilSub::CurriedSub::Curry

HTH

答案 2 :(得分:1)

我必须说我不完全理解你的问题,但匿名子程序可能会帮助你

my $id = (somehow get the ID);

my %users_menu = (
    "l" => ["list users", sub {list_users($id)}], 
                   #now, the id is fixed and the subroutine can be called without arguments
    "n" => ["new user", \&new_user]);

答案 3 :(得分:0)

你可以使用一个闭包。闭包基本上是一个可以“仍然看到”一些外部变量的函数。对于您的示例,您可以使用以下内容:

sub make_list_users {
  my ($lock_id) = @_;
  return sub {
     <body of list_users>
     <do something with $lock_id here>
  }
}

此函数返回一个“关闭”$lock_id的匿名函数,因此名称为“closure”。而不是写

my %users_menu = (
 "l" => ["list users", \&list_users],
 "n" => ["new user", \&new_user]);
你写了

my %users_menu = (
 "l" => ["list users", make_list_users($id)],
 "n" => ["new user", make_new_user($id)]);

请注意,如果没有\&,我们希望代码在此处执行。您的代码仍然会调用

$$options{$choice}[1](); # no arguments

因为make_list_users的结果与之前一样是子程序引用,除了它具有锁定ID作为“内部信息”。不,$lock_id不是全局变量,它是make_list_users的简单局部变量,并且每次运行make_list_users时都会重新设置。唯一的技巧是返回的子例程会记住它的值。

闭包实际上甚至比这更强大:子例程也可以更改(赋值)它关闭的任何变量,而不会影响其他实例使用的闭合变量(即,您可以从{{返回两个不同的子例程) 1}}在同一时间)。

此外,关闭同一个变量的两个或多个闭包都会看到此变量的相同实例,并且可以使用此“秘密通道”将消息传递给彼此!

另见What's a closure?