Perl编码规范

1.命名规则

文件命名

文件名称统一用英文字母(大小写)、数字和下划线的组合,长度一般不超过20个字符,文件命名体现功能的含义,正式发布版本不能加入作者信息。Perl Scripts 文件的扩展名必须是".pl",Perl Module文件的扩展名必须是".pm"。
例如:

lucent_file_parser.pl
lucent_used_module.pm
标识符

采用语法模板来定义标识符的名字,命名必须有一定的实际意义,由英文字母组成,中间可以根据语义的连续性,使用下划线连接。
(1)变量
局部变量必须由小写字母和下划线组成,常量名必须由大写字母和下划线组成。由多个单词组成的名字里,使用下划线""把多个单词分开。全局变量以’g’开头,其余部分的命名规则和局部变量相同。每个全局变量必须有注释说明其作用。
use strict语句称为pragma,它放在脚本的开头,它会强制我们在定义变量时使用my关键字声明变量。my关键字将变量的范围限制为局部。它使代码更易读,更不容易出错。如果你没有使用my关键字声明变量,那么创建的变量将是全局的,尽量避免使用,这样可以将变量的范围缩小到需要它的位置。
尽量不要使用过于简短的变量简写(除非是标准的简写模式)。
尽量不要使用如$x,$y等意义不太明确的名称。
尽量不要使用太长的变量名称。
例如:
my $next_node;
(2)包和类
包、类的命名采用大小写混合、首字母大写的方法。
例如:
IO::Controller
(3)标识符缩写
标识符缩写时要保留单词的开始字母,不是辅音字母的简写。
例如:

    use List::Util qw( max );
    DESC:
    for my $desc (@orig_strs) {
        my $len = length($desc); # $len来自length
        next DESC if ($len > $UPPER_LIM);
        $max_len = max($max_len, $len);
    }

(4)函数
由小写字母、下划线组成。
例如:

sub max
{
   ……
}
sub get_msc_name
{
  ……
}
布尔类型

boolean类型的变量,或返回boolean类型的值的函数,在命名时要反映其属性,必须用is或者has开头。
例如:

    sub is_valid;
    sub is_metadata_available_for;
    sub has_end_tag;
    my $has_loading_finished;
    my $has_found_bad_record;
数组和哈希

数组类型的变量采用复数,hash类型的变量采用单数。要用undef显式释放变量空间。
例如:

    my @events;
    my @handlers;
    my @unknowns;
    my %option;
    my %title_of;
    my %is_available;

2.注释

所有注释可用英文或中文书写,尽量使用英文注释。保持注释和代码的完全一致,修改程序时,必须修改相应的注释。注释的行数一般应在程序总行数的1/5到1/3。禁止出现错别字。注释应该语义明确,避免出现二义性。

文件头部注释

每个含有源代码的文件必须在文件开始有关于该文件的介绍性注释。其中列出文件名、创建者、创建日期、功能描述、版本信息、版权声明;如果对文件进行了修改,应该在文件头中说明修改人、修改日期、修改原因,并变更文件的版本信息,最新版本信息放到最前面。
格式为:

#*********************************************************
# FileName: lucent_file_parser.pl
# Creator: Phonix <phonix@gmail.com.cn>
# Create Time: 2006-01-09
# Description: This is the proof-of-concept code for the
#           Windows denial-of-serice attack described by
#           the Razor team (NTBugtraq, 19-May-00).
# CopyRight: Copyright © Bright Ocean Inter-Telecomm,All rights reserved.
# Revision: V1.0.0
# ModifyList:
#      Revision: V1.1.1
#      Modifier: Phonix 
#   ModifyTime: 2006-01-17
#   ModifyReason: fix the bug of ……
#
#   Revision: V1.1.0
#   Modifier: Phonix
#   ModifyTime: 2006-01-16
#   ModifyReason: add mysql&oracle db support
#*********************************************************
文件中注释

建议在文件中标识出修改部分的起止位置。
例如:

# add mysql&oracle db support begin
    ……
# add mysql&oracle db support end
函数注释

在每个函数前必须写描述性注释。说明这个函数的功能、参数和函数的返回值。
格式为:

#*******************************************************************
# Function Name: calc_time($datetime, $delta)
# Description: This function calculate the new datetime. 
# Parameters:
#   1. $datetime is the base time, taking the format of 'yyyy-mm-dd hh:mm:ss'
#   2. $delta is the time which should be add to the $datetime. A positive value increase the time
#      while the negative vale decrease the time
# Return:
#      A new time string is returned, also taking the format of 'yyyy-mm-dd hh:mm:ss' 
#*********************************************************************
程序块注释

程序块注释用于说明程序中的关键算法、使用某种技巧的代码以及修改、测试、阅读时必须加以注意的代码。
格式为:

#*********************************************************************
#注释内容
#......
#********************************************************************
语句注释

用于对特定程序语句进行说明,建议采取在语句行末尾说明的方法,同时注释换行后也要对齐。格式为:

    my @names = (
        'Damian',    # Primary key
                    # the key is 
        'Matthew',   # Disambiguator
        'Conway',   # General class or category
    );

3.代码布局

括号

建议括号、插入语可以采用两种方式之一,但是在一个程序里选定那种方式之后,那么要至始至终保持一致。
(1)方式一
格式为:

    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";
        }
    }

(2)方式二
括号对{}对必须位于同一列,独占一行,并且和{}之外的语句行对齐

    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";
        }
    }
关键字

把关键字和其他的内容分开,关键字if, while, for,else…后面必须接一个空格。ifwhile语句必须使用’{‘和’}’括起语句体,即使只有一行代码。建议不使用单行的if语句。
例如:

    for my $result (@results) {
        print_sep( );
        print $result;
    }
    while ($min < $max) {
        my $try = ($max - $min) / 2;
        if ($value[$try] < $target) {
            $max = $try;
        }
        else {
            $min = $try;
        }
    }
    if ($condition){
      $i++;
    }
子程序和变量

不要把子程序或变量和其后的括号部分分开。
例如:

my @candidates = get_candidates($marker);#正确
my @candidates = get_candidates ($marker);#错误
代码缩排

缩进采用四个空格,或一个TAB(1 TAB 设置成四个空格)。

代码块

不要把两句话放在一行,每行只能写一个语句。
例如:

chomp $record;                                        #正确
next RECORD if $record eq $EMPTY_STR;                 #正确
chomp $record; next RECORD if $record eq $EMPTY_STR;  #错误
代码长度

每个函数体的语句行不能超过100行(不包括注释,一个分号算一行)。每行长度不要超过78个字符,超过该长度时,必须考虑换行,从低优先级的操作符处分割长表达式, 在赋值符前断开长的语句。
例如:
正确:

push (@steps, $steps[-1]
                 + $radial_velocity * $elapsed_time
                 + $orbital_velocity * ($phase + $phase_shift)
                 - $DRAG_COEFF * $altitude);
$predicted_val = $average + $predicted_change * $fudge_factor;

错误:

push (@steps, $steps[-1] + $radial_velocity
                 * $elapsed_time + $orbital_velocity
                 * ($phase + $phase_shift) - $DRAG_COEFF
                 * $altitude);
$predicted_val = $average
                     + $predicted_change * $fudge_factor;
操作符

二元运算符(算术运算符, 赋值运算符等)的两边都要接空格,低级操作符(如:+-)两边各有两个空格,高级操作符(如:*%)两边各有一个空格。尽量使用andor而不要使用&&||,请注意他们的区别。
在运算符'->'两边不要使用空格,在一元操作符和操作数两边不要使用空格。
可以使用括号来表示运算的先后顺序。
例如:
正确:

my $displacement
        = $initial_velocity * $time  +  0.5 * $acceleration * $time**2;
my $price
        = $coupon_paid * $exp_rate  +  ($face_val + $coupon_paid) * $exp_rate**2;

错误:

my $displacement=$initial_velocity*$time+0.5*$acceleration*$time**2;
my $price=$coupon_paid*$exp_rate+(($face_val+$coupon_val)*$exp_rate**2);
语句结束符

在每个语句后边要填加分号,分号之前尽量不加空格。
例如:

while (my $line = <>) {
        chomp $line;
        if ( $line =~ s{\A (\s*) -- (.*)}{$1#$2}xms ) {
            push @comments, $2;
        }
        print $line;
    }
代码排列

数组或Hash的赋值采用垂直排列。
例如:
正确:

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},
    );

错误:

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},
    );

非末端表达式

采用中间变量代替长表达式。
例如:
正确:

my $next_step = $steps[-1]
                    + $radial_velocity * $elapsed_time
                    + $orbital_velocity * ($phase + $phase_shift)
                    - $DRAG_COEFF * $altitude
                    ;
    add_step( \@steps, $next_step, $elapsed_time);

错误:

    add_step( \@steps, $steps[-1]
                       + $radial_velocity * $elapsed_time
                       + $orbital_velocity * ($phase + $phase_shift)
                       - $DRAG_COEFF * $altitude
                       , $elapsed_time);
功能块顺序

在每个Perl Scripts中,每个功能块之间必须有一个空行。主程序为main()函数,功能块出现顺序如下:

use modules;

global variable 定义

main定义

sub routine 定义

4.数值和表达式

字符串界定符

需要用变量替换的字符串用双引号,否则用单引号。
例如:

my $spam_name = "$title $first_name $surname";
my $pay_rate  = "$minimal for maximal work";
my $spam_name = 'Dr Lawrence Mwalle';
my $pay_rate  = '$minimal for maximal work';
常量

使用字符常量,而不要直接用数值。
例如:
正确:

use Readonly;
    Readonly my $MOLYBDENUM_ATOMIC_NUMBER => 42;
    # and later...
print $count * $MOLYBDENUM_ATOMIC_NUMBER;

错误:

print $count * 42;
字符串

(1)两行
对于两行的字符串,要用“.”进行连接。
例如:
正确:

$usage = "Usage: $0 <file> [-full]\n"
. "(Use -full option for full dump)\n";

错误:

$usage = "Usage: $0 <file> [-full]
(Use -full option for full dump)";

(2)多于两行
对于多于两行,要采用如下格式,例如:
正确:

    $usage = <<"END_USAGE";
    Usage: $0 <file> [-full] [-o] [-beans]
    Options:
        -full  : produce a full dump
        -o     : dump in octal
        -beans : source is Java
    END_USAGE

错误:

    $usage = "Usage: $0 <file> [-full] [-o] [-beans]\n"
             . "Options:\n"
             . "    -full  : produce a full dump\n"
             . "    -o     : dump in octal\n"
             . "    -beans : source is Java\n"
             ;
哈希变量

Hash变量的定义采用双箭头(=>)方式。
例如:
正确:

    %default_service_record  = (
        name    => '<unknown>',
        rank    => 'Recruit',
        serial  => undef,
        unit    => ['Training platoon'],
        duty    => ['Basic training'],
    );

错误:

    %default_service_record  = (
        'name',   '<unknown>',
        'rank',   'Recruit',
        'serial', undef,
        'unit',   ['Training platoon'],
        'duty',   ['Basic training'],
    );

5.函数

调用语法

调用时要使用圆括号,不管是否有参数。
例如:

fix();
coerce($input, $INTEGER, $ROUND_ZERO);
函数返回

在函数中要进行显式的return返回。
例如:

    sub set_terseness {
        my ($terseness) = @_;
        my $default_terseness = $terseness;
        return;  # Explicitly return nothing meaningful
    }

6.编程惯例

使用use strict

所有Perl Scripts 文件中必须在开始使用“use strict;”,进行严格的语法检查,便于查找错误。

避免使用内部变量名称

避免使用Perl内部变量。使用“use English;”装入Perl内部变量的符号名称。使用my来限定变量的作用域。下面是一些Perl内部变量名称的对应关系。

      $_      $ARG
      @_      @ARG
      $!      $ERRNO
      $?      $CHILD_ERROR
      $$      $PID
      $0      $PROGRAM_NAME
      $.      $INPUT_LINE_NUMBER
      $|      $OUTPUT_AUTOFLUSH
      $@      $EVEL_ERROR
      $&      $MATCH
      $`      $PREMATCH
      $'      $POSTMATCH
      $+      $LAST_PAREN_MATCH
      $/      $RS
      $\      $ORS
      $<      $UID
      $>      $EUID
      $(      $GID
      $)      $EGID
      $]      $PERL_VERSION
      $?      $CHILD_ERROR
避免使用goto

避免使用goto语句(只有在从多重循环的内部跳出时才可以使用)。除非能够特别有效的增加程序的效率并且不影响程序良好结构的特殊情况。

语法检查(辅助工具)

使用-cw选项检查Perl程序的语法。
正确:

perl -cw -Mdiagnostics file.pl             # check syntax with warnings on
nt;       # Perl 5.004_04, define constants
use Env;          # instead of $ENV{'HOME'}; Shortens the usage, but do not 
# mix normal variables 
# with environment variables.
使用标准模块

尽量使用标准库函数、公共函数和开发库中已有的函数和模块,使用FileHandle模块来处理文件的读写。尽量使用以下的标准Perl模块:

use strict;         # helps you to locate syntax errors or uncertainties.
use integer;        # if you don't need floating point math,it will speed Perl up.
use constagives you `carp' and `croak'
use English;        # gives symbolic names, like $! ==> $ERRNO
use Getopt::Long;   # --posix command line option handling
use Cwd;           # platform independent cwd()
use File::Basename;  # don't invent your own wheel of this.
use File::Find;       # don't use system("find . -name ...")...
use File::copy;      # don't use system("cp this that");
use File::patch;      # instead of system("mkdir");
use File::stat;       # readable: $st = stat($file), $st->mode
use DirHandle;      # OO form of `readdir'
use Text::Tabs       # un/expand tabs in text
use Text::ParseWords; # Parse text into tokens, understands embedded
                         # quotes. @a = &quotewords("[ +]", 0, $_);
                         # a+b, "a b" + c
use Socket;         # socket handling
use Sys::Hostname;  # don't invent your own wheel
use Net::Ping       # unix ping, check if host is online
use Time::Local     # time manipulations
其他

1、编码、测试、注释,是程序员的三项基本工作,它们是同等重要的。
2、可靠性第一,可读性第二,效率第三。只有在极个别必须强调效率的部分,可以是可靠性第一,效率第二,可读性第三。
3、首先是正确,其次是优美。
4、无法证明你的程序没有错误。因此,在新编写完一段程序后,应该测试通过后再继续编码。
5、改正一个错误的同时,可能会引起新的错误。因此,在修改bug前,首先考虑对其他程序的影响。修改后,应该对程序进行完整的测试,而不是只对修改部分进行测试。
6、避免使用很多个参数的函数。
7、函数应该只有一个出口。
8、循环应该只有一个出口,避免多个出口。
9、复杂的下标使用适当的空格。
10、在尽可能小的作用域内定义和使用变量。
11、使用括号,表达复杂表达式中的操作符的优先顺序。
12、循环、分支不要超过五个层次。
13、循环、分支等语句后,即使只有一行代码时,也要使用{}将其括起来。
14、禁止else gotoelse return
15、重复使用的、完成相对独立功能的算法、代码,应该抽象为公共模块。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容

  • Android 编码规范 1. 前言 这份文档是 Google Java Code Style 的译文,并稍有添加...
    人失忆阅读 439评论 0 3
  • Introduction 介绍 本文提供的Python代码编码规范基于Python主要发行版本的标准库。Pytho...
    帅气的Lucky阅读 659评论 0 0
  • 1 文件与目录 1.1 文件命名 1 文件与目录的命名可以使用的字符为[A-Z, a-z, 0-9, ., _, ...
    rick_2016阅读 11,435评论 0 9
  • JavaScript编码规范 1 前言 2 代码风格 2.1 文件 2.2 结构 2.2.1 缩进 2.2.2 空...
    江湖相望知冷暖阅读 446评论 0 0
  • 介绍 本文档给出了Python代码的编码约定。 该样式指南会随着时间的流逝而发展,因为会发现其他约定,而过去的约定...
    Eazow阅读 462评论 0 0