Perl最佳实践读书笔记-第二章(代码部署)
代码风格最重要的是一致性!找出一种你或你的团队喜欢的风格,并坚持下去!
括号方式
使用K&R风格的括号,即把开口大括弧放在控制该代码块的行尾,接下来的代码缩进,然后在独立的一行放置闭口大括号。如下
for my $name (@names) {
for my $word ( anagrams_of(lc $name) ) {
print "$word\n" ;
}
}
列表元素占据多行时,按如下方式安排
my @names = (
'Damian', # 主键
'Matthew', # 明义
'Conway', # 一般类或类别
);
与其他风格相比, K&R风格有一个显著的优点,就是看到的代码行数最少。反对K&R风格的论据主要是认为此风格不好找到控制块的起始括弧,起始只要从结束括弧向上滚动,碰到和它对齐的控制块,在此行的末尾就是起始的括弧了。另外可以使用编辑器的快捷键来匹配括弧,在vi中,是%。
关键字
在关键字和后续的小括弧之间放置一个空格,这样不至于和子程序调用混淆起来。比如下面的while和if
while ($min < $max) {
my $tr = ($max - $min) / 2;
if ($value[$try] < $target) {
$max = $try;
}
else {
$min = $try;
}
}
在大控制块开口大括弧与前面的小括弧之间放置空格,如下,@result后面的小括弧和大括弧之间有个空格。
for my $result (@results) {
print_sep();
print $result;
}
子程序和变量
子程序和随后的小括弧之间不要加空格,下面这样写是恰当的。
my $result = &get_result($param) ;
这样写则不好辨认
my $result = &get_result ($param) ;
数组或者哈希变量与后面的括弧之间不要加空格,下面这样写是恰当的。
$candidates[$i]
= $incumbent{ $candidates[$i]{$region} };
内置函数
内置函数调用时无需加小括弧,这样便于区分内置函数和用户子过程。一些导入的子程序,调用时也不用加括弧。比如List::Util中的first和max。本条规则有一个例外,就是有时候需要强调优先级,那么仍需要加小括弧。如下面的substr。
while (my $record = <$results_file>) {
chomp $record;
my ($name, $votes) = split "\t", $records;
print 'Votes for ',
substr($name, 0, 10),
": $vostes\n";
}
键和索引
对于多层嵌套的数据结构,很容易产生冗长的表达式,比如下面这个。
$candidates[$i] = $incumbent{$candidates[$i]{get_region())};
在索引表达式的{}内部前后各加一个空格,则可读性大大提高!
$candidates[$i] = $incumbent{ $candidates[$i] {get_region() } };
如果不是嵌套的数据结构,但是变量名很长,也应加上空格,便于阅读。
print $incumbent{ $largest_gerrymandered_constituency };
运算符
运算符不要与运算数紧紧贴在一起,用适当个数的空格来区分优先级是不错的选择,下面的表达式中,+左右各有两个空格,而*左右各有一个空格,这表示*的优先级比+高,而**左右没有空格,表示优先级最高。
my $displacement
= $initial_velocity * $time + 0.5 * $acceleration * $time**2;
分号
在Perl中,分号是语句的分隔符,而不是语句的结束符,所以一个代码块的最后一条语句并不需要加分号,但是我们通常都加上,原因有二:
第一,分号告诉编译器,该语句已经完成,虽然我们能看出语句完成,但是编译器看不出来。
第二,日后添加代码时,避免不必要的错误。比如下面这个例子。最后一条语句后没有分号。
while (my $line = <>) {
chomp $line;
...
print $line
}
过了些日子,我们在print语句后面加了点东西,如下。
while (my $line = <>) {
chomp $line;
...
print $line
$src_len += length;
}
遗憾的是,这段代码并不能按预期的结果工作,实际上,它将被解析为下面这样。这种错误十分隐晦。
while (my $line = <>) {
chomp $line;
...
print $line ($src_len += length);
}
逗号
逗号一般作为参数和列表元素的分隔符,当作为列表元素分隔符时,最后一个元素后面也要加逗号,这样做的好处有二:
一,便于重新排列列表中的元素。
二,便于向列表尾端添加新的元素。
代码行的长度
代码行的长度不宜过长,书上说设置为78列最佳,如果用的是vi,可以这样设置,set textwidth=78
缩排
使用4列缩排,也有使用8列的,因为打印机使用8列缩排?这样的话,你的代码在哪里看起来都一样,但是我们使用4列。不要使用制表符来缩排,因为不同设备上制表符的宽度是不同的。更不要把制表符和空格混搭。
代码块
为map和grep设置单独的代码块,如下。
my @clean_words
= map {
my $word = $_;
$word =~ s/$EXPLETIVE/[DELETED]/gxms;
$word;
} @raw_words;
逻辑上相关联的代码放在一起,前面加上注释,块与块之间以空格分离。
else
不要紧贴的else,要另起一行,如下
if () {
}
else {
}
而不是下面这样
if () {
} else {
}
垂直对齐
比如下面这些,都是很好的对齐方式,大大增加了代码的可读性。
my @months = qw(
January February March
April May June
July August September
October November December
);
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';
对于数组或者散列的赋值,键要对齐,值要对齐,索引及大括弧都要对齐才好看,如下是最佳对齐方式。
$ident{ name } = standerdize_name($name);
$ident{ age } = time - $birth_date;
$ident{ status } = 'active';
断开长行
若行中有运算符,那么从低优先级的地方断开,且最后的分号单独一行,以标示行的结束。如下。
push @steps, $steps[-1]
+ $radial_velocity * $elapsed_time
+ $orbital_velocity * ($phase + $phase_shift)
- $DRAG_COEFF * $altitude
;
换行的位置很重要,比如下面的方法就比上面的好一些。
push @steps, $steps[-1]
+ $radial_velocity * $elapsed_tiem
+ $orbital_velocity * ($phase + $phase_shift)
- $DRAG_COEFF * $altitude
;
如果非要再高优先级的运算符处断开,那么继续缩进一下。
push @steps, $steps[-1]
+ $radial_velocity * $elapsed_time
+ $orbital_velocity
* ($phase + $phase_shift)
- $DRAG_COEFF * $altitude
;
若有赋值运算符,则赋值运算符从新开一行,如下
$predicted_val
= $average + $predicted_change * $fudge_factor;
辅助工具
使用perltidy可以帮助格式化代码,可以从sourcefrog上下载。
==