Perl的一些优雅功能或用途是什么?

时间:2009-03-13 04:17:01

标签: perl

  

什么? Perl漂亮吗? Elegant?他一定是在开玩笑!

确实,那里有一些丑陋的Perl。有些人,我的意思是很多。我们都看过了。

  嗯,呃,这是象征汤。不是吗?

是的,有符号。就像'数学'有'符号'一样。只是我们程序员更熟悉标准的数学符号。我们开始接受母语中的符号,无论是ASM,C还是Pascal。 Perl刚决定再多做一些。

  

嗯,我认为我们应该摆脱所有不必要的符号。使代码看起来更好。

这样做的语言已经存在。它被称为Lisp.(很快,perl 6。)

  

好的,聪明的家伙。事实是,我已经可以发明自己的符号了。它们被称为功能和方法。此外,我们不想重新发明APL

哦,假冒的另一个自我,你真好笑!这是真的,Perl可以很漂亮。它也可能非常丑陋。使用Perl,TIMTOWTDI

那么,你最喜欢的Perl代码是什么?

14 个答案:

答案 0 :(得分:28)

Perl便于使用列表/哈希来实现命名参数,我认为这些参数非常优雅,并且对自记录代码有很大的帮助。

my $result = $obj->method(
    flux_capacitance       => 23,
    general_state          => 'confusion',
    attitude_flags         => ATTITUDE_PLEASANT | ATTITUDE_HELPFUL,
);

答案 1 :(得分:24)

我最喜欢的优雅Perl代码并不一定优雅。它们是元优雅,并且允许您摆脱许多Perl开发人员已经陷入的所有不良习惯。我需要几个小时或几天才能将它们全部展示给它们应有的细节,但作为一个简短列表,它们包括:

如果你懒得关注链接,我最近就上述大部分内容做了talk at Linux.conf.au。如果你错过了它,那就是video of it on-line(ogg theora)。如果你懒得观看视频,我今年作为OSCON的教程做了大量扩展的演讲(题为正确地做Perl )。

一切顺利,

答案 2 :(得分:19)

我很惊讶没有人提到Schwartzian Transform.

my @sorted =
  map  { $_->[0] }
  sort { $a->[1] <=> $b->[1] }
  map  { [ $_, expensive_func($_) ] }
@elements;

在没有愚蠢的运营商的情况下,

my $file = do { local $/; readline $fh };

答案 3 :(得分:16)

是否有用户希望程序处理的文件列表?不想意外处理程序,文件夹或不存在的文件?试试这个:

@files = grep { -T } @files;

而且,就像魔法一样,你已经淘汰了所有不合适的条目。不想无声地忽略它们?在最后一行之前添加此行:

warn "Not a file: $_" foreach grep { !-T } @files;

为每个无法处理标准错误的文件打印一条漂亮的警告消息。不使用grep的同样的事情看起来像这样:

my @good;
foreach(@files) {
  if(-T) {
    push @good, $_;
  } else {
    warn "Not a file: $_";
  }
}

grep(以及map)可用于缩短代码,同时保持其可读性。

答案 4 :(得分:11)

“或死”构造:

open my $fh, "<", $filename
    or die "could not open $filename: $!";

使用qr //创建语法:

#!/usr/local/ActivePerl-5.10/bin/perl

use strict;
use warnings;
use feature ':5.10';

my $non_zero         = qr{[1-9]};
my $zero             = qr{0};
my $decimal          = qr{[.]};
my $digit            = qr{$non_zero+ | $zero}x;
my $non_zero_natural = qr{$non_zero+ $digit*}x;
my $natural          = qr{$non_zero_natural | $zero}x;
my $integer          = qr{-? $non_zero_natural | $zero}x;
my $real             = qr{$integer (?: $decimal $digit)?}x;

my %number_types = (
    natural => qr/^$natural$/,
    integer => qr/^$integer$/,
    real    => qr/^$real$/
);

for my $n (0, 3.14, -5, 300, "4ever", "-0", "1.2.3") {
    my @types = grep { $n =~ $number_types{$_} } keys %number_types;
    if (@types) {
        say "$n is of type", @types == 1 ? " ": "s ", "@types";
    } else {
        say "$n is not a number";
    }
}

用于分解重复代码的匿名子程序:

my $body = sub {
    #some amount of work
};

$body->();
$body->() while $continue;

而不是

#some amount of work
while ($continue) {
    #some amount of work again
}

基于散列的调度表:

my %dispatch = (
    foo => \&foo,
    bar => \&bar,
    baz => \&baz
);

while (my $name = iterator()) {
    die "$name not implemented" unless exists $dispatch{$name};
    $dispatch{$name}->();
}

而不是

while (my $name = iterator()) {
    if ($name eq "foo") {
        foo();
    } elsif ($name eq "bar") {
        bar();
    } elsif ($name eq "baz") {
        baz();
    } else {
        die "$name not implemented";
    }
}

答案 5 :(得分:9)

我最喜欢的一个例子是Perl实现的阶乘计算器。在Perl 5中,它看起来像这样:

use List::Util qw/reduce/;
sub factorial {
    reduce { $a * $b } 1 .. $_[0];
}

如果数字为&lt; = 1或字符串,则返回false;如果传入数字,则返回数字(如果是分数则向下舍入)。

期待Perl 6,看起来like this

sub factorial {
    [*] 1..$^x
}

而且(从上面链接的博客中)您甚至可以将其作为运算符实现:

sub postfix:<!>(Int $x) {
    [*] 1..($x || 1)
}

然后在代码中使用它,如下所示:

my $fact5 = 5!;

答案 6 :(得分:9)

带有构造函数,getter / setter和类型验证的三行类:

{
    package Point;
    use Moose;

    has ['x', 'y'] => (isa => 'Num', is => 'rw');
}

package main;
my $point = Point->new( x => '8', y => '9' );

$point->x(25);

答案 7 :(得分:7)

如果你有一个逗号分隔的标志列表,并想要一个查找表,你所要做的就是:

my %lookup = map { $_ => 1 } split /,/, $flags;

现在你可以简单地测试你需要哪些标志:

if ( $lookup{FLAG} ) {
    print "Ayup, got that flag!";
}

答案 8 :(得分:6)

我很惊讶没有人提到过这个。在我看来,这是一个杰作

#!/usr/bin/perl
                                           $==$';
                                         $;||$.| $|;$_
             ='*$ (                  ^@(%_+&~~;# ~~/.~~
         ;_);;.);;#)               ;~~~~;_,.~~,.* +,./|~
    ~;_);@-,  .;.); ~             ~,./@@-__);@-);~~,.*+,.
  /|);;;~~@-~~~~;.~~,.           /.);;.,./@~~@-;.;#~~@-;;
  ;;,.*+,./.);;#;./@,./        |~~~~;#-(@-__@-__&$#%^';$__
   ='`'&'&';$___="````"  |"$[`$["|'`%",';$~=("$___$__-$[``$__"|
              "$___"|       ("$___$__-$[.%")).("'`"|"'$["|"'#").
        '/.*?&([^&]*)&.*/$'.++$=.("/``"|"/$[`"|"/#'").(";`/[\\`\\`$__]//`;"
        |";$[/[\\$[\\`$__]//`;"|";#/[\\\$\\.$__]//'").'@:=("@-","/.",
       "~~",";#",";;",";.",",.",");","()","*+","__","-(","/@",".%","/|",
        ";_");@:{@:}=$%..$#:;'.('`'|"$["|'#')."/(..)(..)/".("```"|"``$["|
        '#("').'(($:{$'.$=.'}<<'.(++$=+$=).')|($:{$'.$=.'}))/'.("```;"|
        "``$[;"|"%'#;").("````'$__"|"%$[``"|"%&!,").${$[};`$~$__>&$=`;$_=
       '*$(^@(%_+&@-__~~;#~~@-;.;;,.(),./.,./|,.-();;#~~@-);;;,.;_~~@-,./.,
        ./@,./@~~@-);;;,.(),.;.~~@-,.,.,.;_,./@,.-();;#~~@-,.;_,./|~~@-,.
          ,.);););@-@-__~~;#~~@-,.,.,.;_);~~~~@-);;;,.(),.*+);;# ~~@-,
           ./|,.*+,.,.);;;);*+~~@-,.*+,.;;,.;.,./.~~@-,.,.,.;_)   ;~~~
             ~@-,.;;,.;.,./@,./.);*+,.;.,.;;@-__~~;#~~@-,.;;,.*   +);;
               #);@-,./@,./.);*+~~@-~~.%~~.%~~@-;;__,. /.);;#@-   __@-
                 __   ~~;;);/@;#.%;#/.;#-(@-__~~;;;.;_ ;#.%~~~~  ;;()
                      ,.;.,./@,.  /@,.;_~~@- ););,.;_   );~~,./  @,.
                      ;;;./@,./|  ~~~~;#-(@- __,.,.,.    ;_);~~~ ~@
                       -~~());;   #);@-,./@,  .*+);;;     ~~@-~~
                       );~~);~~  *+~~@-);-(   ~~@-@-_      _~~@-
                       ~~@-);;   #,./@,.;.,    .;.);@      -~~@-;
                       #/.;#-(   ~~@-@-__      ~~@-~~       @-);@
                       -);~~,    .*+,./       |);;;~        ~@-~~
                        ;;;.;     _~~@-@     -__);.         %;#-(
                        @-__@      -__~~;#  ~~@-;;          ;#,.
                        ;_,..         %);@-,./@,            .*+,
                        ..%,           .;.,./|)             ;;;)
                        ;;#~            ~@-,.*+,.           ,.~~
                       @-);            *+,.;_);;.~         ~););
                      ~~,.;         .~~@-);~~,.;.,         ./.,.;
                      ;,.*+        ,./|,.);  ~~@-         );;;,.(
                    ),.*+);                              ;#~~/|@-
                  __~~;#~~                                $';$;;

答案 9 :(得分:3)

我绝对 Black Perl(链接到重写为在Perl 5下编译的版本)。它编译,但据我所知,它实际上没有做任何事情。

这就是语言学家从语用学角度而不是从理论角度学习语言所能获得的。

继续前进,你可以考虑人们抱怨的Perl作为pidgin Perl(非常有用,但没有表现力,并且要小心尝试表达任何复杂的内容),以及@pjf所讨论的内容作为“适当的”Perl,莎士比亚,海明威,休谟等语言。 [编辑:错误,虽然比休谟更容易阅读,而且比莎士比亚的日期更少。] [重新编辑,希望不如海明威酗酒]

答案 10 :(得分:2)

加入对mapgrep的热爱,我们可以编写一个简单的命令行解析器。

my %opts = map { $_ => 1 } grep { /^-/ } @ARGV;

如果需要,我们可以在@ARGV中将每个标志设置为它的索引:

my %opts = map { $ARGV[$_] => $_ } grep { $ARGV[$_] =~ /^-/ } 0 .. $#ARGV;

这样,如果一个标志有一个参数,我们可以得到这样的参数:

if( defined( $opts{-e} ) ) {
  my $arg = $ARGV[ $opts{-e} ];
  # do -e stuff for $arg
}

当然,有些人会哭,我们正在重新发明轮子,我们应该使用getopt或其中的一些变体,但老实说,这是一个相当容易重新发明的轮子。另外,我不喜欢getopt。

如果你不喜欢这些行的长度,你总是可以使用中间变量或只是方便的换行符(嘿,Python狂热分子?你听说过吗?我们可以把一行代码放在两行上吧仍然有效!)让它看起来更好:

my %opts = map  { $ARGV[$_] => $_   }
           grep { $ARGV[$_] =~ /^-/ } 0 .. $#ARGV;

答案 11 :(得分:1)

此文件解析机制紧凑且易于自定义(跳过空白行,跳过以X开头的行等)。

open(H_CONFIG, "< $file_name") or die("Error opening file: $file_name! ($!)");
while (<H_CONFIG>)
{
   chomp;         # remove the trailing newline
   next if $_ =~ /^\s*$/; # skip lines that are blank
   next if $_ =~ /^\s*#/; # skip lines starting with comments
   # do something with the line
}

我在不同的构建情况下使用这种类型的构造 - 我需要预先或后期处理有效负载文件(S记录等)或C文件或收集“智能构建”的目录信息。 / p>

答案 12 :(得分:1)

我最喜欢的优雅Perl功能是它使用不同的运算符来表示数值和字符串值。

my $string = 1 . 2;
my $number = "1" + "2";
my $unambiguous = 1 . "2";

将此与其他动态语言(如JavaScript)进行比较,其中“+”用于连接和添加。

var string = "1" + "2";
var number = 1 + 2;
var ambiguous = 1 + "2";

或者是动态语言,如Python和Ruby,需要在字符串和数字值之间进行类型强制。

string = "1" + "2"
number = 1 + 2
throws_exception = 1 + "2"

在我看来Perl认为这是对的,其他语言也是如此错误。

答案 13 :(得分:-17)

像我这样的打字员经常会因为使用分号而感到痉挛,并且几乎无理性地担心使用分号,我们开始在python格式的文件中编写Perl代码。 :)

e.g。

>>> k = 5
>>> reduce(lambda i,j: i*j, range(1,k+1),1)
120
>>> k = 0
>>> reduce(lambda i,j: i*j, range(1,k+1),1)
1