命名重要吗?重要!!可以类比现实中的姓名,姓名当然重要,它不止是一个符号,同时饱含其他方面的希冀。同样,在编写程序时,对变量、函数等的命名也极其重要,不合适的命名可能来自不恰当的概念体系,某个糟糕的命名很可能会引起其他人的混淆,为出错埋下了种子。。。
这么多年过去了,命名依然不是我的强项。之前看过几篇文章,大体意思是说:“命名是令每个程序员的头疼的事。”这在一定程度上抚慰了我受伤的小心脏。下面给出的是Quora和Ubuntu论坛的一个投票结果,不见得客观,放在这里是想告诉读者:当你又在愁名字的问题,不要叹气,因为好多人都这样。
下面我们进入主题,好的命名是什么样的呢?下面是我的个人看法,求同存异:
1.名字要有意义
放第一条是有原因的:如果代码是给机器看的,我们也就不用这么大费周章。实际上,编译器处理代码的时候,它才不管你名字起得怎么样,只要名字满足标识符的规则就可以。
我们的代码当然是给人看的,所以名字一定要有意义,否则,即使是自己,长时间以后,也会看不懂自己写的代码,更不用说别人。
比如,给“用户名单”命名为:std::vector<int> vec;
vec
完全给不了读者任何信息,这个命名对于这个业务域是没有意义的。
2.名字长度与作用域大小正相关
作用域限定着名字的可见性,作用域越大,名字的可见范围越大,相应地,名字冲突的概率越大。而较小作用域的名字,对程序的其他部分不可见,所以允许一定程度的重名,只要不在一个作用域下即可。
所以,通常名字的作用域越大,名字长度也相应的越长,这是为了减少重名的概率;相反,名字作用域越小,可以使用较短的名字。
3.采用适当的命名法
命名法的主要目的,是通过名字的结构来区分其类型,比如类型名,使用名词,方法名使用动宾短语等等。
常见的主要命名法有:
- 匈牙利命名法
- 骆驼命名法
- 帕斯卡命名法
- ...
很多语言推荐的命名风格一般都是其中一种,或几种的组合。使用一致的命名法,可以减少理解的成本,也容易维护代码的一致性。
匈牙利命名法主要在Windows下使用较多,目前我在开发使用的代码规则就是基于匈牙利命名法,这种方式我不推荐使用,在下一篇文章会单独说明。骆驼命名法和帕斯卡命名法是较常用的方式,按照自己的喜好选择即可。
4、谓词函数与普通的函数要有区分
函数通常都是对某个对象执行某个操作,用动宾短语命名即可,如果是成员函数,可以省略宾语,因为宾语是在对象上下文中隐含的。
有一类函数称之为谓词函数,其返回bool值,通常是判断某种事物的性质,用这套命名规则命名就不合适了。目前常见的几种处理方式:
- 使用形容词表示谓词
比如,C++标准库判断容器的是否为空的empty
成员函数,Haskell中判断列表是否空的函数null
。
从原理上是没问题的,但不太可行,原因是:很多英文单词通常既是动词,又是名词,很让人混淆。比如,我见过的某类库中的清空容器的成员函数就命名为Empty
,很明显这个empty
是动词。
这种方式对于非英语语种的我们来说不易执行,所以不建议使用。 - 使用加前缀方式
常见的是加Is
前缀,上面的例子改写为IsEmpty
、IsNull
,这样从形式上就区分开了。
推荐使用。 - 使用后缀方式
Scheme中通过使用加后缀?
表示谓词,而Lisp中使用后缀p
,这两种方式都是比较可行的方式。但我更喜欢Scheme的方式,因为符号更容易辨识。
但考虑到某些语言,标识符不允许?
,所以采用哪种还要看具体的环境。
5.常量与变量要区分
常量和变量如果要全部区分,也是不可行的。最好能区分全局作用域下的常量和变量,能对程序外部的调用起到明显的提示作用:“这是个常量,不要改变它”。
6.函数与宏要区分
起因在于看到了Windows下max
和min
的实现,竟然使用宏实现的,而通过名字完全看不出来。大家都知道,宏跟函数在某些情况下是有细微区别的,如果开发者不知道这个函数是用宏实现的,也就避免不了这些坑了。
宏名通常全大写,以区分函数。
7.上下文一致性
这条规则体现了概念的一致性,一个名字要在上下文中代表同一个东西,这样不会让读代码的人疑惑。
在日常工作中,出现问题最多就是这个,尤其发生在多个人或部门之间。对同一个事物,不同的人、不同的部门的命名是不一样的,导致在后续的代码维护、数据分析中出现的问题较多。
8.体现专业性
有些语言支持Unicode字符的命名,然后你就看到了包含汉语、日语等的名字;有些名字出现了汉语拼音;有些概念明明有专业的名词表达,非使用自己定义的名字;有些名字在业务域有现成的,而非自己重新造词。。。
专业性的表现:使用当前语境下最合适的词。
上面6条也是我对自己的要求,与君共勉!!
请关注我的公众号哦。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。