2021 年 12 月 17 日星期五,是 Perl 编程语言](https://github.com/Perl/perl5/commit/8d063cd8450e59ea1c611a2f4f5a21059a2804f1)的[三十四岁生日,巧合的是,今年发布了 5.34版本。那里有很多 Perl 开发人员没有跟上语言及其生态系统的最新(和不太近期)改进,所以我想我可能会列出一批。 (您可能在 5 月的帖子“Perl 现在可以做到这一点!”中看到过其中的一些)

feature杂注

Perl v5.10 于 2007 年 12 月发布,随之而来的是feature,这是一种在不破坏向后兼容性的情况下启用新语法的方法。您可以按名称启用单个功能(例如,use feature qw(say fc);用于sayfc关键字),或使用基于引入它们的 Perl 版本的功能包。例如,以下内容:

use feature ':5.34';

进入全屏模式 退出全屏模式

...给你相当于:

use feature qw(bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state switch unicode_eval unicode_strings);

进入全屏模式 退出全屏模式

男孩,这是一口。 _功能包很好。_如果您指定最低要求的 Perl 版本,例如use v5.32;,则相应的包也会获得隐式加载。如果您是use v5.12;或更高版本,则免费启用strict模式。所以只说:

use v5.34;

进入全屏模式 退出全屏模式

最后,单行代码可以使用-E开关而不是-e来启用该版本 Perl 的所有功能,因此您可以在命令行上说以下内容:

perl -E 'say "Hello world!"'

进入全屏模式 退出全屏模式

代替:

perl -e 'print "Hello world!\n"'

进入全屏模式 退出全屏模式

当您尝试节省一些输入时,这很棒。

experimental编译指示

有时,新的 Perl 特性需要在](https://perldoc.perl.org/perlpolicy#experimental)块周围的几个版本中被[驱动,然后它们的行为才会稳定下来。这些实验记录在实验页面中,通常,您需要use feature(见上文)和no warnings语句才能安全地启用它们。或者您可以简单地将列表传递给use experimental您想要的功能,例如:

use experimental qw(isa postderef signatures);

进入全屏模式 退出全屏模式

不断扩大warnings类别

2000 年 3 月,Perl 5.6发布,随之而来的是将-w命令行开关扩展为一个细粒度控制系统,用于警告可以打开和关闭的“可疑构造”取决于词法范围。最初的26 个主要类别和 20 个子类别已将扩展为 31 个主要类别和 43 个子类别,包括对上述实验功能的警告。

正如相关的 Perl::Critic 政策所说,“使用警告并注意他们所说的话,可能是提高代码质量的唯一最有效的方法。”如果您必须违反警告(可能是因为您正在修复一些遗留代码),您可以将此类违规行为隔离到小范围和单独的类别中。如果您想更进一步并在开发过程中使这些类别的安全子集成为致命的,请查看 CPAN](https://metacpan.org/pod/strictures)上的[限制模块。

使用记录其他最近引入的语法 Syntax::Construct

并非 Perl 语法的每一个新部分都启用了feature保护。其余的是 E. Choroba 在 CPAN](https://metacpan.org/pod/Syntax::Construct)上的[Syntax::Construct 模块。不必记住哪个版本的 Perl 引入了什么,Syntax::Construct 允许您只声明您使用的内容,并在有人试图在旧的不受支持的版本上运行您的代码时提供有用的错误消息。在它和featurepragma 之间,您可以避免许多令人头疼的时刻,并为您的用户提供升级或解决方法的机会。

使内置函数抛出异常autodie

许多 Perl 的内置函数只在失败时返回 false,需要开发人员每次检查文件是否可以执行opened 或system命令。词法autodiepragma将它们替换为引发异常的版本,带有对象可以询问更多详细信息。无论出现多少深层次的功能或方法问题,您都可以选择抓住它并做出适当的响应。这导致我们......

try/catch异常处理和Feature::Compat::Try

今年的 Perl v5.34 版本引入了实验性try/catch语法用于异常处理,在处理问题时其他语言的用户应该看起来更熟悉使用[块(https://perldoc.perl.org/functions/eval#Block-eval)和测试[41010186特殊$@变量。如果您需要与旧版本的 Perl(回到 v5.14)保持兼容,只需使用 CPAN](https://metacpan.org/pod/Feature::Compat::Try)中的[Feature::Compat::Try 模块自动选择 v5.34 的本机try/catch或Syntax::Keyword::Try提供的功能。

可插拔关键字

上述 Syntax::Keyword::Try 是通过在 2010 年的 Perl v5.12中引入可插入关键字机制而成为可能的。Future::AsyncAwait异步编程库和用于新的面向对象 Perl 语法的Object::Pad测试平台也是如此。如果您对 C 和Perl 的 XS 胶水语言很方便,请查看 Paul “LeoNerd” Evans 的XS::Parse::Keyword模块,以便在开发自己的语法模块方面取得优势。

用版本和块定义packages

Perl v5.12 还通过启用package命名空间声明来帮助减少混乱到还包括版本号,而不需要单独的our $VERSION = ...;v5.14 进一步细化package为[在代码块 17]1001 中指定命名空间声明可以与词法范围相同。将两者放在一起为您提供:

package Local::NewHotness v1.2.3 {
    ...
}

进入全屏模式 退出全屏模式

代替:

{
    package Local::OldAndBusted;
    use version 0.77; our $VERSION = version->declare("v1.2.3");
    ...
}

进入全屏模式 退出全屏模式

我知道我更愿意做什么。 (尽管您可能还希望use Syntax::Construct qw(package-version package-block);与旧安装一起提供帮助,如上述。)

//定义或运算符

这是来自 Perl v5.10](https://perldoc.perl.org/perl5100delta#Defined-or-operator)的轻松胜利[:

defined $foo ? $foo : $bar # replace this
$foo // $bar               # with this

进入全屏模式 退出全屏模式

和:

$foo = $bar unless defined $foo # replace this
$foo //= $bar                   # with this

进入全屏模式 退出全屏模式

非常适合为变量分配默认值。

state变量只初始化一次

说到变量,是否希望在下次进入范围时保留其旧值,例如中的sub?用state而不是my声明它。在Perl v5.10,您需要使用闭包代替。

使用say保存一些输入

Perl v5.10 的大量增强功能还包括say函数,它处理print使用换行符处理字符串或字符串列表的常见用例。您的代码中的噪音更少,并为您节省了四个字符。不去爱的种种?

注意未实现的代码与...

...省略号语句(俗称“yada-yada”)为尚未实现的代码提供了一个简单的占位符。它解析OK,但如果执行会抛出异常。希望您的测试覆盖率(或至少静态分析)将在您的用户之前捕获它。

使用eachkeysvalues循环和枚举数组

eachkeysvalues函数始终能够对哈希进行操作。Perl v5.12 及更高版本使它们也可以在数组上工作。后两者主要是为了保持一致性,但您可以使用each同时迭代数组的索引和值:

while (my ($index, $value) = each @array) {
    ...
}

进入全屏模式 退出全屏模式

这在非平凡循环](https://metacpan.org/pod/Perl::Critic::Policy::Community::Each)中可能是[问题,但我发现它在快速脚本和单行代码中很有帮助。

delete local散列(和数组)条目

曾经需要delete来自块内的哈希条目(例如,来自%ENV的环境变量或来自%SIG的信号处理程序)?Perl v5.12 允许您使用和delete local执行此操作。

配对散列片

跳转到2014 的 Perl v5.20,新的%foo{'bar', 'baz'}语法使您能够对哈希](https://perldoc.perl.org/perldata#Key%2FValue-Hash-Slices)的子集进行[切片,并且其键和值保持不变。对于挑选或将许多散列聚合为一个非常有帮助。例如:

my %args = (
    verbose => 1,
    name    => 'Mark',
    extra   => 'pizza',
);
# don't frob the pizza
$my_object->frob( %args{ qw(verbose name) };

进入全屏模式 退出全屏模式

成对阵列切片

不要被遗漏,你也可以用同样的方式对数组切片,在这种情况下返回索引和值:

my @letters   = 'a' .. 'z';
my @subset_kv = %letters[16, 5, 18, 12];
# @subset_kv is now (16, 'p', 5, 'e', 18, 'r', 12, 'l')

进入全屏模式 退出全屏模式

更易读的解引用

Perl v5.20 引入了和v5.24 去实验更易读后缀取消引用语法用于导航嵌套数据结构。代替使用{braces}或在标识符左侧平滑符号,您可以使用后缀符号和星号:

push @$array_ref,    1, 2, 3; # noisy
push @{$array_ref},  1, 2, 3; # a little easier
push $array_ref->@*, 1, 2, 3; # read from left to right

进入全屏模式 退出全屏模式

如此多的 Web 开发是通过JSON将复杂的数据结构分解和分解,所以我欢迎这样的事情来减少认知负荷。

when作为语句修饰符

从 Perl v5.12开始,您可以使用实验性开关功能的when关键字作为后缀修饰符。例如:

for ($foo) {
    $a =  1 when /^abc/;
    $a = 42 when /^dna/;
    ...
}

进入全屏模式 退出全屏模式

但我不推荐whengivengiven的smartmatch操作,因为它们是在 2013 年的 Perl v5.18中作为实验重新进行的,并且由于它们的[棘手的行为]1]1 而一直如此。我在二月份使用稳定的语法](https://phoenixtrap.com/2021/02/14/switching-up-my-switches/)写了大约[一些替代方案。

简单的类继承与use parent

有时在旧的面向对象的 Perl 代码中,你会看到use base作为一个编译指示来建立从另一个类的继承。较旧的仍然是直接操作包的特殊@ISA数组。在大多数情况下,都应该避免使用use parent,这是在 Perl v5.10.1](https://perldoc.perl.org/perl5101delta#parent)中添加到核心的[。

请注意,如果您遵循Perl 面向对象教程的建议并从 CPAN 中选择了 OO 系统,请使用其子类化机制(如果有的话)。Moose、Moo和Class::Accessor 的“鹿角”模式都提供了extends的功能;[Object::Pad 在其class关键字上提供:isa属性](https://metacpan.org/pod/Object::Pad#:isa)。

使用isa运算符测试类成员资格

作为提供给所有 Perl 对象的isa()方法的替代方案,Perl v5.32 引入了实验性isa中缀运算符:

$my_object->isa('Local::MyClass')
# or
$my_object isa Local::MyClass

进入全屏模式 退出全屏模式

后者可以采用裸词类名或字符串表达式,但更重要的是,它更安全,因为如果左参数未定义或不是blessed 对象引用,它也会返回 false。旧的isa()方法在前一种情况下会抛出异常,并且如果在$my_object实际上是与isa()的参数相同或继承自isa()的参数的类名的字符串时作为类方法调用,则可能会返回 true。

词法子程序

在 Perl v5.18 中引入和在 2017 年的 Perl v5.26中进行了去实验,现在您可以在子声明之前使用mystate或两个真正的私有函数,或者。和方法,如这个 2018 Dave Jacoby 博客和作为Neil Bowers 的 2014 年调查的私有函数技术的一部分。

子程序签名

在过去的一年里,我已经写了和广泛地介绍了关于签名和替代品,所以我不会在这里重复。我只想补充一点,Perl 5 Porters开发邮件列表是,在过去的一个月里,齐心协力解决了剩余的问题,以使这个特性成为非实验性的。流行的 Mojolicious 实时 Web 框架也提供了启用签名的快捷方式并在示例中广泛使用它们。

缩进此处的文档与<<~

Perl 长期以来一直使用 shell 风格的“here-document” 语法来嵌入多行带引号的文本字符串。从 Perl v5.26开始,您可以在定界字符串前面加上~字符,Perl 将允许缩进结束定界符以及从嵌入文本中去除缩进。这允许更多可读的嵌入式代码,例如运行 HTML 和 SQL。例如:

if ($do_query) {
    my $rows_deleted = $dbh->do(<<~'END_SQL', undef, 42);
      DELETE FROM table
      WHERE status = ?
      END_SQL
    say "$rows_deleted rows were deleted."; 
}

进入全屏模式 退出全屏模式

更易读的链式比较

当我在学校学习数学时,我的老师和教科书经常将多重比较和不等式描述为一个单一的表达方式。不幸的是,当我学习编程时,我看到的每一种计算机语言都要求将它们分解为一系列and(或&&)运算符。使用 Perl v5.32,这不再是:

if ( $x < $y && $y <= $z ) { ... } # old way
if ( $x < $y <= $z )       { ... } # new way

进入全屏模式 退出全屏模式

它更简洁,噪音更小,更像普通数学的样子。

自记录命名正则表达式捕获

Perl 富有表现力的正则表达式匹配和文本处理能力是传奇的,尽管过度使用和使用不当的可读性增强常常使人们远离它们(以及一般的 Perl)。我们经常使用正则表达式从匹配的模式中提取数据。例如:

if ( /Time: (..):(..):(..)/ ) { # parse out values
    say "$1 hours, $2 minutes, $3 seconds";
}

进入全屏模式 退出全屏模式

Perl v5.10](https://perldoc.perl.org/perl5100delta#Named-Capture-Buffers)中引入的命名为的捕获组、[使模式更加明显,并且对其数据的检索不那么神秘:

if ( /Time: (?<hours>..):(?<minutes>..):(?<seconds>..)/ ) {
    say "$+{hours} hours, $+{minutes} minutes, $+{seconds} seconds";
}

进入全屏模式 退出全屏模式

更易读的正则表达式字符类

/x正则表达式修饰符已经通过告诉解析器忽略大多数空格来提高可读性,允许您将复杂的模式分解为间隔组和带有代码注释的多行。使用 Perl v5.26,您可以指定/xx也忽略[bracketed]字符类中的空格和制表符,将其变为:

/[d-eg-i3-7]/
/[!@"#$%^&*()=?<>']/

进入全屏模式 退出全屏模式

......进入这个:

/ [d-e g-i 3-7]/xx
/[! @ " # $ % ^ & * () = ? <> ']/xx

进入全屏模式 退出全屏模式

使用repragma 设置默认正则表达式标志

从 Perl v5.14开始,编写use re '/xms';(或正则表达式修饰符标志的任意组合)将打开这些标志,直到该词法范围结束,从而省去了每次都记住它们的麻烦。

s///rtr///r无损替代

s///替换和tr///音译运算符通常直接更改其输入,通常与=~绑定运算符结合使用:

s/foo/bar/; # changes the first foo to bar in $_
$baz =~ s/foo/bar/; # the same but in $baz

进入全屏模式 退出全屏模式

但是,如果您想保持原件不变,例如在处理具有map的字符串数组时怎么办?对于 Perl v5.14 及更高版本,添加/r标志,这会在副本上进行替换并返回结果:

my @changed = map { s/foo/bar/r } @original;

进入全屏模式 退出全屏模式

Unicode 大小写折叠与fc更好的字符串比较

Unicode 和字符编码通常是复杂的野兽。自 v5.6](https://perldoc.perl.org/perl56delta#Unicode-and-UTF-8-support)以来,Perl 已经处理了 Unicode,并且在随后的几十年中一直与修复和支持更新的标准保持同步。如果您需要测试两个字符串是否相等,请使用 Perl v5.16中引入的fc函数[。

使用<<>>更安全地处理文件参数

<>空文件句柄或“菱形运算符”通常用于while循环以处理来自标准输入(例如,从另一个程序通过管道传输)或来自命令行上的文件列表的每行输入。不幸的是,它使用 Perl 的open函数](https://perldoc.perl.org/functions/open#open-FILEHANDLE,EXPR)的[形式来解释特殊字符,例如管道 (|),这将允许它不安全地运行外部命令。使用 Perl v5.22](https://perldoc.perl.org/perl5220delta#New-double-diamond-operator)中引入的<<>>“双菱形”运算符[强制open仅将所有命令行参数视为文件名。对于较旧的 Perls,perlop 文档建议使用ARGV::readonly CPAN 模块。

@INC更安全地加载 Perl 库和模块

[Perl v5.26 删除了所有程序默认从当前目录](https://perldoc.perl.org/perl5260delta#Removal-of-the-current-directory-(%22.%22)-from-@INC 加载模块的能力,关闭了一个安全漏洞,该漏洞最初被识别并修复为CVE-2016–1238在以前的版本中包括脚本。如果您的代码依赖于这种不安全的行为,则v5.26 发行说明包括有关如何适应的步骤。

HTTP::Tiny包括简单的 HTTP/1.1 客户端

为了在可能没有curlwget等外部工具的情况下引导对 Web 上的CPAN的访问,Perl v5.14 开始包含 HTTP::Tiny 模块。如果您需要一个没有依赖关系的简单 Web 客户端,您也可以在您的程序中使用它。

Test2: 下一代 Perl 测试框架

从古老的Test::Builder(许多人熟悉的Test::More库的基础)分叉和重构,Test2从 Perl v5 开始包含在核心模块库中。 26。我最近使用Test2::SuiteCPAN 库而不是 Test::More 对](https://phoenixtrap.com/tag/test2/)进行了[实验,它看起来相当不错。我也对Test2::Harness'支持线程、分叉和预加载模块以减少测试运行时间很感兴趣。

Task::Kensho: 从哪里开始推荐 Perl 模块

安装 Perl 时可能不包括最后一项,但我在其中找到了一系列备受推崇的 CPAN 模块,用于完成从异步编程到XML的各种常见任务。使用它作为起点或交互式选择适合您项目的库组合。


就这样:Perl 最初 34 年的 34 个特性、增强和改进的选择。你最喜欢什么?我错过了什么吗?在评论中让我知道。


封面图片:“我的生日蛋糕”byWesley Bowler在CC BY-NC-SA 2.0 下获得许可

Logo

ModelScope旨在打造下一代开源的模型即服务共享平台,为泛AI开发者提供灵活、易用、低成本的一站式模型服务产品,让模型应用更简单!

更多推荐