Category: BookNotes Keywords: Code Layout
刚拿起盗版电子书《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 世界是自由的世界。