Perl通过原生子程序签名提升级别

虽然Perl 5.20版本预计要到春天才会发布,但现在您已经可以使用最新的Perl开发版本中的子程序签名功能了。

要求

您需要安装最新版本的Perl开发版本(v5.19.9)。您可以使用Perlbrew来获取。

$ perlbrew install perl-5.19.9
$ perlbrew switch perl-5.19.9

或者您可以从cpan.org下载并构建Perl v5.19.9。

一旦安装了5.19.9,您将需要实验性发行版。您可以在命令行使用cpan进行安装。

$ cpan experimental

子程序签名解释

子程序签名是子程序参数的正式列表。您可以像这样声明子程序签名:

use experimental 'signatures';

sub echo ($message) {
    print "$message\n";
}

在这个例子中,“($message)”是子程序签名。这表示所有对echo子程序的调用都必须传递一个参数。当调用子程序时,参数将被分配给$message,并在子程序的范围内可用。

默认值

签名还可以为其参数声明默认值。让我们给echo子程序添加一个默认消息:

use experimental 'signatures';

sub echo ($message = 'Hello World!') {
    print "$message\n";
}

现在当不带参数调用子程序时,$message的值将默认为“Hello World!”。

子程序签名还可以声明可选的和贪婪的参数。如果您想查看示例,请查看Perl的官方文档中的新子程序签名条目。

参数检查

将签名添加到子程序中可以为该子程序的所有调用启用参数检查。例如,以下代码在运行时将生成错误:

use experimental 'signatures';

sub echo ($message) {
    print "$message\n";
}

echo(); # missing argument
$ perl echo.pl
Too few arguments for subroutine at echo.pl line 3.

如果传递了过多的参数,Perl也会引发错误。

use experimental 'signatures';

sub echo ($message) {
    print "$message\n";
}

echo('hello', 'world'); # too many arguments
$ perl echo.pl
Too many arguments for subroutine at echo.pl line 3.

这很有帮助,因为它避免了在子程序内部编写样板参数检查代码的需要。但请注意;由于没有值检查,以下代码不会引发参数错误。

use experimental 'signatures';

sub echo ($message) {
    print "$message\n";
}

echo(undef); #undef is an argument

更简洁的代码

您可以将那些令人讨厌的变量赋值从子程序中删除。再见(以及永别)吧:

sub ugly_code {
    my ($arg1, $arg2, arg3) = @_;
    ...
}

而欢迎这个:

sub fine_code ($arg1, $arg2, arg3){
    ...
}

更多增强功能即将到来

与功能齐全的Method::Signatures模块相比,原生子程序签名实现是一个最小化的版本。Perl原生子程序签名的主要赞助商Peter Martini已经确认计划在未来添加类型检查、别名、只读副本和命名参数。他预计这些功能中的每一个都将带来速度上的改进。

重新审视Python和Perl的比较

在《快速Python书,第二版》的第5页(The Quick Python Book, Second Edition)中,作者比较了等效的Perl和Python函数的可读性。在作者看来,Python代码比Perl代码更易读。这是一个稻草人论点,因为Perl示例是使用“婴儿Perl”编写的,但让我们使用Perl的原生子程序签名功能重新审视这个例子。这是未修改的Python示例:

def pairwise_sum(list1, list2):
    result = []
    for i in range(len(list1)):
        result.append(list1[i] + list2[i])
    return result

这是原始的Perl代码示例:

sub pairwise_sum {
    my($arg1, $arg2) = @_;
    my(@result) = ();
    @list1 = @$arg1;
    @list2 = @$arg2;
    for($i=0; $i < length(@list1); $i++) {
        push(@result, $list1[$i] + $list2[$i]);
    }
    return(\@result);
}

这是重构后的Perl版本:

sub pairwise_sum {
    my ($arg1, $arg2) = @_;
    return map { $arg1->[$_] + $arg2->[$_] } 0 .. $#$arg1;
}

这段代码比原始的Perl代码更简洁、更短。它也比Python示例更短。但是,它是更简洁的吗?使用子程序签名,我们可以做得更好:

sub pairwise_sum ($arg1, $arg2) {
    return map { $arg1->[$_] + $arg2->[$_] } 0 .. $#$arg1;
}

您可以看到,使用子程序签名为我们节省了一行参数赋值代码。现在没有争议:Perl代码比Python示例更短、更简洁。太棒了!

结论

子程序签名在技术上对Perl来说是一次飞跃,对Perl社区来说是一次推动。看到显著的语言进步是令人鼓舞的,而且还有更多的发展在路上。有了后缀解引用、新的性能改进以及现在的子程序签名,Perl 5.20 将成为自 5.10 以来最重要的版本。2014 年春天,我们期待着!

2014-02-24:文章更新以纠正错误检查实现、Perl 代码示例并阐明 Peter Martini 在 Perl 内核签名开发中的作用。

喜欢这篇文章吗?帮助一下我们,转发它!


这篇文章最初发布在 PerlTricks.com

标签

David Farrell

David 是一位职业程序员,他经常 推文博客 关于代码和编程艺术。

浏览他们的文章

反馈

这篇文章有什么问题吗?通过在 GitHub 上打开一个 issue 或 pull request 来帮助我们。