如何在Perl中使用函数样式进行编码?

Rit*_*ose 4 perl functional-programming

你怎么样:

  1. 有一个sub回报sub

    要么

  2. 将文本作为代码执行

在Perl?

另外,我如何拥有匿名函数存储状态?

Eth*_*her 16

sub返回一个sub作为coderef:

# example 1: return a sub that is defined inline.
sub foo
{
    return sub {
        my $this = shift;
        my @other_params = @_;

        do_stuff();
        return $some_value;
    };
}

# example 2: return a sub that is defined elsewhere.
sub bar
{
    return \&foo;
}
Run Code Online (Sandbox Code Playgroud)

可以使用该eval函数执行任意文本:请参阅perldoc -f eval中的文档:

eval q{print "hello world!\n"};
Run Code Online (Sandbox Code Playgroud)

请注意,如果您正在评估从用户输入中提取的任何内容,这是非常危险的,并且通常是一种不好的做法,因为您通常可以在coderef中定义代码,如上面的示例中所示.

您可以使用状态变量(perl5.10中的new)或带有高于sub本身的变量作为闭包来存储状态:

use feature 'state';
sub baz
{
    state $x;
    return ++$x;
}

# create a new scope so that $y is not visible to other functions in this package
{
    my $y;
    sub quux
    {
        return ++$y;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 字符串`eval`几乎总是一个坏主意,很难.我能想到的唯一有意义的地方是`require`一个带有裸字语义的模块:`eval'需要$ module";`.我知道必须有一些其他有意义的案例,但我的观点是它们很少而且很远. (9认同)
  • 绝对.初学者抓住"EVAL"作为一个锤子来砸钉子所有的想法,但实际上它却是最好的工具箱极少数情况下的最底部保持的工具. (2认同)

dao*_*oad 7

返回子程序引用.

这是一个简单的例子,它创建了一个关闭值的子引用:

my $add_5_to = add_x_to(5);

print $add_5_to->(7), "\n";

sub add_x_to {
    my $x = shift;

   return sub { my $value = shift; return $x + $value; };

}
Run Code Online (Sandbox Code Playgroud)

你也可以像这样使用命名的subs:

sub op {
    my $name = shift;

    return $op eq 'add' ? \&add : sub {};
}

sub add {
    my $l = shift;
    my $r = shift;

    return $l + $r; 
}
Run Code Online (Sandbox Code Playgroud)

您可以使用eval任意字符串,但不要使用它.代码很难读取,它重新启动编译,这会减慢所有内容.有少数情况下,字符串评估是工作的最佳工具.任何时候字符串评估似乎都是一个好主意,你几乎肯定会用另一种方法更好.

几乎任何你想用字符串eval做的事情都可以用闭包来实现.


Sin*_*nür 5

使用sub关键字可以轻松返回潜艇.返回的子关闭它使用的词法变量:

#!/usr/bin/perl

use strict; use warnings;

sub mk_count_from_to {
    my ($from, $to) = @_;
    return sub {
        return if $from > $to;
        return $from ++;
    };
}

my $c = mk_count_from_to(-5, 5);

while ( defined( my $n = $c->() ) ) {
    print "$n\n";
}
Run Code Online (Sandbox Code Playgroud)

5.10引入了状态变量.

使用Perl执行文本是完成的eval EXPR:

EXPR解析并执行返回值就像它是一个小的Perl程序一样.首先解析表达式的值(它本身在标量上下文中确定),如果没有任何错误,则在当前Perl程序的词汇上下文中执行,以便之后保留任何变量设置或子例程和格式定义.请注意,每次eval执行时都会解析该值

执行任意字符串打开巨大的安全漏洞.


Mat*_*iva 5

您可以创建匿名子例程并通过引用访问它们; 这个引用当然可以分配给标量:

my $subref = sub { ... code ... }
Run Code Online (Sandbox Code Playgroud)

或从另一个子程序返回

return sub { ... code ... }
Run Code Online (Sandbox Code Playgroud)

如果需要存储状态,可以使用外部作用域中定义的词法变量创建闭包,如:

sub create_func {
    my $state;
    return sub { ... code that can refer to $state ... }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用eval运行代码