Perl 简单的效率和可读性



我有一个关于perl效率和可读性的问题

我有一个变量可以采用几个值 (5-6) 之一。有时我想检查这是否是一个特定的值,有时我想检查它是否是几个选项之一。我在代码中的许多地方(在不同的函数中)都做出了这种决定,我想让它尽可能"紧凑"。

例如,说

my $mode; # can be any of qw(one two three four five six)
if ($mode eq 'one') {
    #do code
}
if ($mode eq 'one' or $mode eq 'two' or $mode eq 'three') {
    #do more code
}

这当然不是我真正的代码,并且对于有意义的变量名称,我的 if 语句变得相当长并且换行在几行上。

任何帮助不胜感激!

List::MoreUtils模块具有any功能,就像短路grep

use List::MoreUtils qw/any/;
say "correct mode" if any { $_ eq $mode } qw/one two three/;

也就是说,您仍然可以使用 grep ,但这总是测试所有元素,而any在第一个匹配元素之后中止:

say "correct mode" if grep { $_ eq $mode } qw/one two three/;

一个想法。

my %please_name_me;
$please_name_me{$_}++ for qw(one two three);
if ($please_name_me{$mode}) {
    #do something
}

否则我喜欢使用空格:

if (
    'one' eq $mode or
    'two' eq $mode or
    'three' eq $mode
) {
}

这对于智能匹配来说是一个很好的工作,但是运算符已被标记为实验性,可能会从更高版本的 Perl 中删除。

List::Util具有any运算符。但是,要非常小心。List::Util是至少从Perl 5.8.8开始的标准Perl模块。不幸的是,不包括漂亮的any运算符。您需要更新此模块才能使用 any 。但是,first运算符可能足够好,这是软件包的一部分:

use strict;
use warnings;
use feature qw(say);
use autodie;
use List::Util qw(first);
use constant VALID_VALUES => qw(one two three four five);
for my $value ( qw(zero one two three four five six) ) {
    if ( first { $value eq $_ } VALID_VALUES ) {
        say "$value is in the list!";
    }
    else {
        say "Nope. $value is not";
    }
}

由于程序中有use List::Util qw(first);,用户应该意识到first来自List::Util包,他们可以使用perldoc List::Util来查找它。

您也可以只使用grep而忘记List::Util

for my $value ( qw(zero one two three four five six) ) {
    if ( grep { $value eq $_ } VALID_VALUES ) {
        say "$value is in the list!";
    }
    else {
        say "Nope. $value is not";
    }
}

你不应该做的是使用复杂的正则表达式或 if/else 链。这些不一定更清楚,并且会使您的程序更难理解:

if ( $value =~ /^(one|two|three|four|five)$/ ) {
if ( $value eq "one" or $value eq "two" or $value eq "three" ... ) {

如果您决定更改有效的值列表,则必须浏览整个程序才能搜索它们。这就是为什么我把它们变成一个常数。程序中只有一个地方必须修改它们。

有许多选项(TMTOWDI)。 以下是最简单的两个:

if ($mode =~ /^(?one|two|three)$/) { ... }
if (grep { $mode eq $_ } qw(one two three)) { ... }

通过事先进行一些设置,您可以使其更有效率。 执行此操作一次:

 my @modes = qw(one two three);
 my %modes;
 @modes{@modes} = @modes;

然后你的支票变得很简单:

if ($modes{$mode}) { ... }

如果您使用的是 Perl 5.10 或更高版本,则可以使用智能匹配运算符:

if ($mode ~~ ['one', 'two', 'three'])

如果要检查很多很多组合,请考虑将$mode转换为编号位:

if 'one' -> $modeN = 1
if 'two' -> $modeN = 2
if 'three' -> $modeN = 4  etc.

要只选中"一个",if ($modeN == 1) {...

要选中"一"、"二"或"三",请if ($modeN & 7) {...

要选中"二"或"三",请if ($modeN & 6) {...

要选中"一"或("二"和"三"),if ($modeN & 1 || &modeN & 6) {...

这对你有用吗?

最新更新