在日常编程中最烦恼的就是给变量取名,一段好代码,既要能完美地运行,还要能较容易地维护。这就意味着需要让日后维护代码的人能很快地看懂你的代码,而且,在团队合作中,其他开发者也会经常阅读你那部分代码。如果你的代码中充满了a,b,c,a1,a2,a3...那简直就是一个噩梦。因此,好的变量名非常重要。
选择好变量名的注意事项
变量和变量名本质上是同一件事物,因此,变量的好与坏就在很大程度上取决于它的命名的好与坏。
下面举一个糟糕命名的例子
$pp=($cp1)?($cp-1):$cp;$np=($cp$tp)?($cp+1):$tp;$p=newP($pp,$cp,$np,$tp);
这段代码在做什么呢?也许可以大概知道是在计算一些信息,但是,计算的是什么信息呢?$p,$pp,np,$tp等等这些变量代表的是什么呢?讲真,如果没有任何注释,任何人都无法看不懂这段代码想表达的意思。如果写这段代码的人告诉你,这段代码是在计算分页信息,然后实例化一个分页类,那么你应该如何命名呢?
下面是这段代码的另一种写法,看起来更加清晰:
$prev_page_num=($curr_page_num1)?($curr_page_num-1):$curr_page_num);$next_page_num=($next_page_num$total_page_num)?($curr_page_num+1):$total_page_num);$page=newPage($prev_page_num,$curr_page_num,$next_page_num,$total_page_num);
从上面两段代码可以看出,一个好的变量名在可读性和可维护性上是极其重要的。而且好的变量名是易记的。可以通过应用多条原则来实现这些目标。
最重要的命名注意事项
名字要完全、准确地描述出该变量所代表的事物
用名字表达变量所代表的是什么,不包含晦涩的缩写,同时也没有歧义
下表给出一些变量名称的例子,其中有好的也有差的。
变量用途好名字,好描述坏名字,差描述到期的支票累计额runningTotal,checkTotalwritten,ct,checks,CHKTTL,x,x1,x2高速列车的运行速度velocity,trainVelocity,velocityInMphvelt,v,tv,x,x1,x2,train当前日期currentDate,todaysDatecd,current,c,x,x1,x2,date每页的行数linesPerPagelpp,lines,l,x,x1,x2currentDate和todaysDate都是很好的名字,因为它们都完全而且准确地描述出了“当前日期”这一概念。
cd和c是很糟糕的命名,因为它们用了太短的缩写,而且又不具有描述性。
current也很糟,因为它并没有告诉你是当前什么。
date看上去不错,但经过最后推敲它也只是个坏名字,因为这里所说的日期并不是所有的日期均可,而只是特指当前日期,而date本身并未表达出这层含义。
x,x1和x2永远都是坏名字--传统上用x代表一个未知量,如果不希望你的变量所代表的是一个未知量,那么请考虑取一个更好的名字吧。
名字应该尽可能地明确。像x、temp、i这些名字都泛泛可得可以用于多种目的,它们并没有像应该的那样提供足够信息,因此通常是命名上的败笔。以问题为导向
一个好记的名字反映的通常都是问题,而不是解决方案。即,一个好名字通常表达的是什么(What),而不是怎么样(How)。通常来说,如果一个名字反映了计算机的某些方面而不是问题本身,那么它反映的就是“How”而非“What”了。
比如,考虑下面这两个变量命名:inputRec和employeeData。inputRec是一个反映输入、记录这些计算概念的计算机术语。employeeData则直指问题领域,与计算机无关。
类似地,printerReady比bitFlag更能表达打印机的状态;在财务软件里,calcVar比sum来得更准确。
最适当的名字长度
经研究发现,变量名的平均长度在10到16个字符的时候,调试花的力气是最小的。平均名字长度在8到20隔字符的程序也几乎同样容易调试。这并不意味着你的变量名一定要在8到20个字符,它强调的是,如果你查看自己写的代码时发现了很多更短的名字,那么你就需要认真检查,确保这些名字含义足够清晰。
下面展示变量名太长、太短或刚好的示例:
太长:
numberOfPeopleOnTheUsOlympicTeam;numberOfSeatsInTheStadium;maximumNumberOfPointsInModernOlympics
太短:n,np,ntm;n,ms,nsisd;m,mp,max,points
正好:
numTeamMembers,teamMemberCount;numSeatsInStadium,seatCount;teamPointsMax,pointsRecord
变量名中的计算值限定词
很多程序都有表示计算结果的变量:总额、平均值、最大值,等等。如果你要用类似Total、Sum、Average、Max、Min、Record、String、Pointer这样的限定词来修改某个名字,那么请记住把限定词加到名字的最后。
这种方法的优点:
变量名中最重要的那部分,即为这一变量赋予主要含义的部分应当位于最前面,这样,这一部分就可以显得最为突出,并会被首先阅读到;
避免了由于同时在程序中使用totalRevenue和revenueTotal而产生的歧义
使用统一的编码规范可以提高可读性,简化维护工作。比如,revenueTotal、expenseTotal、revenueAverage、expenseAverage这组名字具有非常优雅的对称性。而totalRevenue、expenseTotal、revenueAverage、averageRevenue这组名字中则看不出什么规律来。
这条规则也有例外,那就是Num的限定词的位置已经是约定俗成的。Num放在变量名的开始位置代表一个总数,比如:numCustomers表示员工的总数。Num放在变量名的结束位置代表一个下标:customerNum表示的是当前员工的序号。这样使用Num常常会带来麻烦,因此,最好的方法是避开这些问题,使用Count或者Total来代表总数,使用Index来指代某个特定的员工。这样,customerCount就代表员工的总数,customerIndex代表某个特定的员工。
变量名中的常用对仗词
对仗词要使用正确,不然会产生歧义。
常用对仗词如下:
begin/end
first/last
locked/unlocked
min/max
next/previous
old/new
opened/closed
visible/invisible
source/target
source/destination
up/down
为特定类型的数据命名
为变量命名,除了通常的考虑事项之外,为一些特定类型数据的命名还要求作出一些特殊的考虑。比如,循环变量、状态变量、临时变量等等。
为循环下标命名
在循环中,最常见的下标变量就是i,j,k,如:
for(i=0;iarrLen;i++){//...}
如果循环下标变量只在循环内部使用,那么如此使用是没问题的,但是,如果该变量需要在循环之外使用,那么就应该为它取一个比i,j,k更有意义的名字。举个栗子,如果你从文件中读取记录,并且需要记下所读取记录的数量,那么类似于redcordCount这样的名字就更合适:
recordCount=0;while(moreScores()){score[recordCount]=GetNextScore();recordCount++;}//usingrecordCount
另一种情况就是嵌套循环,比较常犯的错误就是在想写j的时候写了i,想用i的时候却写了j。
如果你使用了多个嵌套的循环,那么就应该给循环变量赋予更长的名字以提高可读性:
for(teamIndex=0;teamIndexteamCount;teamIndex++){for(eventIndex=0;eventIndexeventCount[teamIndex];eventIndex++){score[teamIndex][eventIndex]=0;}}score[teamIndex][eventIndex]比score[j]给出的信息更多。
注意:如果你一定要用i、j、k,那么不要把它们用于简单循环的循环下标之外的任何场合,避免造成误解。要想避免这种问题,最简单的方法就是使用更好的命名而不是i,j,k。
为状态变量命名
为状态变量取一个比flag更好的名字。最好是把标记看作是状态变量。标记的名字中不应该含有flag,因为你从中丝毫看不出该标记是做什么的。
为清楚可见,标记应该使用枚举变量、具名常量,或用作具名常量的全局变量来对其赋值。
看看下面比较差的标记命名:
if(flag)...if(statusFlag0x0F)...if(printFlag==16)...if(