13 September 2005
This post may be outdated due to it was written on 2005. The links may be broken. The code may be not working anymore. Leave comments if needed.

刚拿起盗版电子书《Perl Best Practices》在读。没机会买正版(没 Visa/MasterCard + 穷),也只好捧着盗版先读下了。
有机会还是挺想买正版书支持下 Damain Conway 先生的。

既然读着,也就随手翻译点,写点东西。不保证任何东西。

Mr Conway 在 Chapter 2 Code Layout 中讲了下代码布局风格,我看着挺好的,也值得推广下。

  • 括弧的风格,推荐第一种而不是二,三。
    # 推荐
    my @names = (
        'Damian',    # Primary key
        'Matthew',   # Disambiguator
        'Conway',    # General class or category
    );

    for my $name (@names) {
        for my $word ( anagrams_of(lc $name) ) {
            print "$word\n";
        }
    }
    # 不推荐这两种

    # Don't use BSD style...
    my @names =
    (
        'Damian',    # Primary key
        'Matthew',   # Disambiguator
        'Conway',    # General class or category
    );

    for my $name (@names)
    {
        for my $word (anagrams_of(lc $name))
        {
            print "$word\n";
        }
    }

    # And don't use GNU style either...

    for my $name (@names)
      {
        for my $word (anagrams_of(lc $name))
          {
            print "$word\n";
          }
      }
  • 将控制流程的关键字与紧跟后面的括弧分开(加一空格)。
    Separate your control keywords from the following opening bracket.
# 推荐
for my $result (@results) {
while ($min < $max) {
if ($value[$try] < $target) {

# 不推荐
for(@results) {
while($min < $max) {
if($value[$try] < $target) {
  • 不要将子程序或变量名与后面的开括弧分开。
    Don't separate subroutine or variable names from the following opening bracket.
# Do
get_candidates($marker);
if open_region($i);
$candidates[$i]{region}

# DONOT
get_candidates ($marker);
if open_region ($i);
$candidates [$i] {region}
  • 对于内建函数没必要带括号的就不要带括号。这样加强可读性。
    Don't use unnecessary parentheses for builtins and "honorary" builtins.
  • 对复杂的键或索引,将其与周围的括弧分开。
    Separate complex keys or indices from their surrounding brackets.
# Do
$candidates[$i] = $incumbent{ $candidates[$i]{ get_region( ) } };
print $incumbent{ $largest_gerrymandered_constituency };

# Do NOT
$candidates[$i] = $incumbent{$candidates[$i]{get_region( )}};
print $incumbent{$largest_gerrymandered_constituency};
  • 使用空格将二元操作符与它的操作数分开。
    Use whitespace to help binary operators stand out from their operands.
 # Do
my $displacement = $initial_velocity * $time  +  0.5 * $acceleration * $time**2;
my $price = $coupon_paid * $exp_rate  +  ($face_val + $coupon_paid) * $exp_rate**2;

# Do NOT
my $displacement=$initial_velocity*$time+0.5*$acceleration*$time**2;
my $price=$coupon_paid*$exp_rate+(($face_val+$coupon_val)*$exp_rate**2);
  • 在每一语句后加分号。但是对于只有一个单独语句的 map 和 grep, 请省略。
    Place a semicolon after every statement.
# Do
if ( $line =~ s{\A (\s*) -- (.*)}{$1#$2}xms ) {
    push @comments, $2;
}
my @sqrt_results = map { sqrt $_ } @results;

# Do NOT
if ( $line =~ s{\A (\s*) -- (.*)}{$1#$2}xms ) {
    push @comments, $2
}
my @sqrt_results = map { sqrt $_; } @results;
  • 在多行列表的每一个值后面加逗号。
    Place a comma after every value in a multiline list.
  • 使用 78 列的行。
    Use 78-column lines.
  • 使用四列的缩进水平(每一缩进为四个空格)。
    Use four-column indentation levels.
  • 使用空格缩进,而不是制表 Tab. 因为在不同的环境下,制表所表现的空格不一。可以用文本编辑器设置只动转换制表。
    Indent with spaces, not tabs.
  • 永远不要在同一行上写两个语句。
    Never place two statements on the same line.
 # Do
chomp $record;
next RECORD if $record eq $EMPTY_STR;

# Do NOT
chomp $record; next RECORD if $record eq $EMPTY_STR;
  • 请使用段落编写代码。将不同的功能的语句分段(同功能的为一段),在每一段前注释这段的用处。
    Code in paragraphs.
  • 不要使用拥挤格式的 else/elsif
    Don't cuddle an else.
# Do
}
else {
}
elsif ($sigil eq '@' && $subsigil eq '?') {

# NOT
} else {
} elsif ($sigil eq '@' && $subsigil eq '?') {
  • 垂直将相关项目排列。
    Align corresponding items vertically.
# Do
my %expansion_of = (
    q{it's}    => q{it is},
    q{we're}   => q{we are},
    q{didn't}  => q{did not},
    q{must've} => q{must have},
    q{I'll}    => q{I will},
);
$name   = standardize_name($name);
$age    = time - $birth_date;
$status = 'active';


# Do NOT
my %expansion_of = (
    q{it's} => q{it is}, q{we're} => q{we are}, q{didn't} => q{did not},
    q{must've} => q{must have}, q{I'll} => q{I will},
);
$name = standardize_name($name);
$age = time - $birth_date;
$status = 'active';
  • 在操作符将长表达式截断。缩进时注意与前面句子相关部分对齐。
    Break long expressions before an operator.
# Do
push @steps, $steps[-1]
             + $radial_velocity * $elapsed_time
             + $orbital_velocity * ($phase + $phase_shift)
             - $DRAG_COEFF * $altitude
             ;

# NOT
push @steps, $steps[-1] +
     $radial_velocity * $elapsed_time +
     $orbital_velocity * ($phase + $phase_shift) -
     $DRAG_COEFF * $altitude;
  • 如果长表达式在语句的中间,可以额外提出来。
    Factor out long expressions in the middle of statements.
# Do
my $next_step = $steps[-1]
                + $radial_velocity * $elapsed_time
                + $orbital_velocity * ($phase + $phase_shift)
                - $DRAG_COEFF * $altitude
                ;
add_step( \@steps, $next_step, $elapsed_time);

# Do NOT
add_step( \@steps, $steps[-1]
                   + $radial_velocity * $elapsed_time
                   + $orbital_velocity * ($phase + $phase_shift)
                   - $DRAG_COEFF * $altitude
                   , $elapsed_time);
  • 总是在可能的低优先级的操作符那而不是高优先级那,将长表达式截断。
    Always break a long expression at the operator of the lowest possible precedence.
# Do
push @steps, $steps[-1]
             + $radial_velocity * $elapsed_time
             + $orbital_velocity
                 * ($phase + $phase_shift)
             - $DRAG_COEFF * $altitude
             ;

# NOT
push @steps, $steps[-1] + $radial_velocity
             * $elapsed_time + $orbital_velocity
             * ($phase + $phase_shift) - $DRAG_COEFF
             * $altitude
             ;
  • 在赋值操作符前将长表达式截断。
    Break long assignments before the assignment operator.
# Do
$predicted_val
    = $average + $predicted_change * $fudge_factor;

# NOT
$predicted_val = $average
                 + $predicted_change * $fudge_factor
                 ;
  • 将三元层叠用列格式排好。
    Format cascaded ternary operators in columns.
 # Do
my $salute = $name eq $EMPTY_STR                      ? 'Customer'
           : $name =~ m/\A((?:Sir|Dame) \s+ \S+) /xms ? $1
           : $name =~ m/(.*), \s+ Ph[.]?D \z     /xms ? "Dr $1"
           :                                            $name
           ;

# NOT
my $salute = $name eq $EMPTY_STR ? 'Customer'
           : $name =~ m/\A((?:Sir|Dame) \s+ \S+)/xms ? $1
           : $name =~ m/(.*), \s+ Ph[.]?D \z/xms ? "Dr $1" : $name;
  • 将长列表加上括弧。
    Parenthesize long lists.
# Do
push @items, (
    "A brand new $item",
    "A fully refurbished $item",
    "A ratty old $item",
);

# NOT
push @items, "A brand new $item"
           , "A fully refurbished $item"
           , "A ratty old $item"
           ;
  • Enforce your chosen layout style mechanically.

当然风格是自己选的,并非强制。 Perl 世界是自由的世界。



blog comments powered by Disqus