基本原则:好的代码,能够减少 "别人" 理解它的时间。 "别人" 不仅指的是 其他人,也可能是 以后的自己

        

1  代码应易理解

1.1  符合习惯

    下面两种形式等效,但方式2 更符合编码习惯,容易理解

// 方式 1
Node* node = list->head;
if (node == NULL) return;

while(node->next != NULL) {
    Print(node->data)
    node = node->next;
}
if(node != NULL) Print(node->data);  

// 方式 2
for (Node* node = list->head; node != NULL; node = node->next)
    Print(node->data);    

1.2  少且易懂

  1)  少 + 易懂

// 多 - if 语句
if(exponent >= 0) {
    return mantissa * (1 << exponent);
} else {
    return mantissa / (1 << -exponent);
}

// 少 - 条件运算符
return exponent >= 0 ? mantissa * (1 << exponent) : mantissa / (1 << -exponent);  

  2)  少 + 不易懂

// 少 - 不易理解
assert ((!(bucket = FindBucket(key))) || !bucket->IsOccupied());

// 多 - 易理解
bucket = FindBucket(key);
if(bucket != NULL) asset(!bucket->IsOccupied());  

 

           

2  封装信息到名字

2.1 命名要贴切

  2.1.1 使用特有的词

    BinaryTree 类中的 Size() 不如 Height()、NumNodes() 或 MemoryBytes() 更明确;Thread 类中 通常是 Kill(),而不是 Stop(),且 Pause() 和 Resume() 成对出现

    常用词语的替代词,如下:

// send = deliver, dispatch, announce, distribute, route
// find = search, extract, locate, recover
// start = launch, create, begin, open
// make = create, set up, build, generate, compose, add, new   

2.1.2  避免通用名

    retval 是 “平方和”,不如 sum_squares 合适  

var euclidean_norm = function (v) {
    var retval = 0.0;
    for (var i = 0; i < v.length; i += 1)
        retval += v[i] * v[i];
    return Math.sqrt(retval);
};  

    如下 tmp 较为合适

if (right < left) {
    tmp = right;
    right = left;
    left = tmp;
}  

    但下例的 tmp 就不如 tmp_file 更明确

tmp_file = tempfile.NamedTemporaryFile()
...
SaveDate(tmp_file, ...)  

    i, j, k 易混淆,不如 clubs_i, members_i, users_i 方便,或简化为 ci, mi, ui

for (int i = 0; i < clubs.size(); i++)
    for (int j = 0; j < clubs[i].members.size(); j++)
        for (int k = 0; k < users.size(); k++)
            if (clubs[i].members[k] == users[j])
                cout << "user[" << j << "] is in club[" << i << "]" << endl;  

2.1.3  使用具体的名

    谷歌早期的 C++编码规范,为了避免编译器自动生成拷贝构造函数和赋值算子,定义了如下宏:

#define DISALLOW_EVIL_CONSTRUCTORS(ClassName) \
  ClassName(const ClassName&); \
  void operator=(const ClassName&);  

    这个名字不如后来的 DISALLOW_COPY_AND_ASSIGN(ClassName) 贴切

    实际上,C++11 有了 delete 关键字,无须使用该宏了,参见 C++11 之 delete 和 default

2.2  附加额外信息

2.2.1  类型

  某些变量,附加额外的信息可以更好的理解,如,一个16进制的变量,命名为 hex_id 比  id 更贴切

// Example: "af84ef845cd8" 
string  hex_id;  

2.2.2  单位

  如下 getTime() 返回值的单位是 ms 而不是 s,可将 _ms 作为后缀加到变量的后面,则会使代码变得更为清晰

var start_ms = (new Date()).getTime(); // top of the page
...
var elapsed_ms = (new Date()).getTime() - start_ms; // bottom of the page
document.writeln("Load time was: " + elapsed_ms / 1000 + " seconds");

   除了时间,还有别的单位:

// 带单位的函数参数
Start (int  delay_secs)
CreateCache (int  size_mb)
ThrottleDownload (float  limit_kbps)
Rotate (float  angle_cw)  

2.2.3  其它属性

  一些有关安全的变量命名,也常需要一些额外的信息

// A password is in "plaintext" and should be encrypted before further processing
std::string  plaintext_password;

// Byte of html have been converted to UTF-8
std::string  html_utf8;

// Incoming data has been "url encoded"
std::string  data_urlenc;  

2.3  格式要求

2.3.1  作用域和缩写

  - 长名长域,短名短域:变量 m 并没有封装任何信息,但是因为只在 if 作用域内有效,所以并不对妨碍代码的理解

  - 善用缩写:当变量名实在太长,可考虑缩写,但要注意团队中的新人,也能理解缩写的含义。如,evaluation 常缩写为 eval,document -> doc,string -> str

  - 去掉无用词:ToString() 优于 ConvertToString(),ServeLoop() 比 DoServeLoop() 简洁

if (debug) {
  map<string,int> m;
  LookUpNamesNumbers(&m);
  Print(m);
}  

2.3.2  下划线和大写

    谷歌 C++ 编码规范中:

    - 类名一般是各个首字母大写,类成员函数名也是如此;

    - 类成员变量名后都带有下划线 "_";

    - 常量命名为 kConstantName,和 #define MACRO_NAME 宏区分

static const int kMaxOpenFiles = 100;
class LogReader {
public:
    void OpenFile(string local_file);
private:
    int offset_;
    DISALLOW_COPY_AND_ASSIGN(LogReader);
};

 

posted on 2017-02-15 10:52  飞鸢逐浪  阅读(740)  评论(0编辑  收藏  举报