如何创建一个接受code块一个Perl子程序 [英] How to create a Perl subroutine that accepts a block of code

查看:92
本文介绍了如何创建一个接受code块一个Perl子程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一组子程序看起来像这样的:

I have a set of subroutines that look like this:

sub foo_1($) {
  my $name = shift;
  my $f; 

  run_something();
  open($f, $name) or die ("Couldn't open $name");
  while (<$f>) {
    //Something for foo_1()
  }
  close($f); 
  do_something_else();

}

和我有这样四个或更多看起来相同,唯一改变的事情是当块体。我想这个抽象和停止复制粘贴围绕code。

And I have like four or more that look the same, the only thing that changes is the body of the while block. I'd like to abstract this and stop copy-pasting the code around.


  • 有没有一种方法,以code子程序接受code块并执行它?

要给予更多的情况下,不同的富子程序读取不同的文件的内容,和数据馈送到一个散列参考不同的有限状态机(FSM)。也许还有一个更聪明的事情比什么,我试图完成的事情。

To give more context, the different foo subroutines are a different Finite State Machine (FSM) that read the contents of different files and feed the data to a hash reference. Maybe there is a more intelligent thing to do than what I am trying to accomplish.

推荐答案

Perl提供了一个调用的子程序的原型,使您可以编写获取类似的内置函数的方式解析用户潜艇系统。要效仿建宏是地图的grep 排序可各取一个块作为他们的第一个参数。

Perl offers a system called subroutine prototypes that allow you to write user subs that get parsed in a way similar to the builtin functions. The builtins that you want to emulate are map, grep, or sort which can each take a block as their first argument.

要做到这一点与原型,使用子名称(安培){...} 其中&安培; 告诉Perl,第一个函数参数可以是一个块(带或不带)或文字子程序 \\&放大器; mysub 。在(安培)原型指定一个且只有一个说法,如果你需要code座后传递多个参数,你可以把它写成(安培; @)这意味着,一个code座后跟一个列表

To do that with prototypes, you use sub name (&) {...} where the & tells perl that the first argument to the function is either a block (with or without sub), or a literal subroutine \&mysub. The (&) prototype specifies one and only one argument, if you need to pass multiple arguments after the code block, you could write it as (&@) which means, a code block followed by a list.

sub higher_order_fn (&@) {
    my $code = \&{shift @_}; # ensure we have something like CODE

    for (@_) {
        $code->($_);
    }
}

这子程序将在列表中通过的每一个元素上运行在块通过。在 \\&放大器; {转变@_} 看起来有点神秘,但它的作用是关闭列表的第一个元素,这应该是一个code座转变。在&放大器; {...} 取消引用值作为一个子程序(调用任何超载),然后在 \\ 立即取引用。如果该值是code REF,则原封不动地返回。如果这是一个重载的对象时,它变成code。如果它不能被强迫code,则会引发错误。

That subroutine will run the passed in block on every element of the passed in list. The \&{shift @_} looks a bit cryptic, but what it does is shifts off the first element of the list, which should be a code block. The &{...} dereferences the value as a subroutine (invoking any overloading), and then the \ immediately takes the reference to it. If the value was a CODE ref, then it is returned unchanged. If it was an overloaded object, it is turned into code. If it could not be coerced into CODE, an error is thrown.

要调用这个函数,你可以这样写:

To call this subroutine, you would write:

higher_order_fn {$_ * 2} 1, 2, 3;
# or
higher_order_fn(sub {$_ * 2}, 1, 2, 3);

(安培; @)的原型,可以让你写的参数作为地图 / 的grep 块一样使用高阶函数的函数时才会起作用。如果你正在使用它作为一个方法,你应该忽略的原型,写这样说道:

The (&@) prototype that lets you write the argument as a map/grep like block only works when using the higher order function as a function. If you are using it as a method, you should omit the prototype and write it this way:

sub higher_order_method {
    my $self = shift;
    my $code = \&{shift @_};
    ...
    $code->() for @_;
}
...
$obj->higher_order_method(sub {...}, 'some', 'more', 'args', 'here');

这篇关于如何创建一个接受code块一个Perl子程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆