〇、什么是卫语句?

下面是摘自维基百科 Wiki 的内容:

在计算机程序设计中,卫(guard)是布尔表达式,其结果必须为,程序才能执行下去。卫语句(guard code 或 guard clause)用于检查先决条件。卫语句的用途,例如:

  • 引用(reference)使用前检查是否为空引用;
  • 处置模式使用一个布尔域,使得释放资源操作成为幂等运算,即多次释放资源等效于只释放一次。

简单来说就是将 if 语句的判断条件进行修改,使其只有为的时候,程序才能继续执行下去。

一、卫语句的应用案例

光看定义,可能不是很好理解,但是在程序中就可以很直观、具体地看出使用不使用卫语句的差别了。

卫语句的使用对于代码结构的扁平化起着至关重要的作用,可很大程度减少阅读代码的难度我认为并不能很有效的提高可读性,仅仅是阅读起来方便,后面我会更详细地说明关于这一点的我的看法)。下面直接看案例:

不使用卫语句的 if 嵌套
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (accounts.find(from) != accounts.end()) { // 检查转账账户是否存在
if (accounts.find(to) != accounts.end()) { // 检查收款账户是否存在
if (amount > 0) { // 检查转账金额是否大于 0
if (accounts[from] >= amount) { // 检查转账账户余额是否足够支付转账金额
// 执行转账操作
accounts[from] -= amount;
accounts[to] += amount;
cout << "转账成功:" << from << " 向 " << to << " 转账 " << amount << " 元。" << endl;
} else {
cout << "转账失败:账户 '" << from << "' 余额不足。" << endl;
}
} else {
cout << "转账失败:转账金额必须大于0。" << endl;
}
} else {
cout << "转账失败:账户 '" << to << "' 不存在。" << endl;
}
} else {
cout << "转账失败:账户 '" << from << "' 不存在。" << endl;
}

可以看出,这种代码嵌套是很不利于阅读的,因为你需要一级一级的去关注这个嵌套层级,而不是逻辑本身。

如果嵌套更多,代码一页展示不下的时候,亦或者代码缩进只有 2 个字符的时候,那这将会是致命的!

不信,你可以尝试去阅读一段这样的代码。相信我,你也会头疼的😫!

下面我将对上述代码使用卫语句进行调整,你再看看是否会好阅读一些呢?

使用卫语句进行调整后的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 卫语句:检查账户是否存在
if (accounts.find(from) == accounts.end()) {
cout << "转账失败:账户 '" << from << "' 不存在。" << endl;
return false;
}
if (accounts.find(to) == accounts.end()) {
cout << "转账失败:账户 '" << to << "' 不存在。" << endl;
return false;
}

// 卫语句:检查转账金额是否有效
if (amount <= 0) {
cout << "转账失败:转账金额必须大于0。" << endl;
return false;
}

// 卫语句:检查账户余额是否足够
if (accounts[from] < amount) {
cout << "转账失败:账户 '" << from << "' 余额不足。" << endl;
return false;
}

// 执行转账操作
accounts[from] -= amount;
accounts[to] += amount;

cout << "转账成功:" << from << " 向 " << to << " 转账 " << amount << " 元。" << endl;

怎么样式?这样是不是就很容易被阅读了😋?

二、关于卫语句的问题

为什么我认为卫语句只能降低代码阅读难度而不是提高可读性?

首先必须承认的是,卫语句确实扁平化了代码结构,使得我们可以更多的关注代码的逻辑本身,而不是“代码结构解析”。

但是,多出口的代码往往会在复杂逻辑中展现弊端,你需要很小心地处理每一个卫语句,并且确保他们的顺序关系。而大量的 return 也会为 BUG 调试带来一定的困难。这一点相信有很多编程人都深有体会!

图 2.1 网友的看法
图 2.2 网友的看法

而上面的例子只是很简单的一个说明,重点是突出卫语句为阅读代码带来的简洁。但是实际上很多工程代码中的逻辑关系将会很复杂,卫语句并不一定就可以提高代码的可读性。

我认为的可读性还是应该偏向于人类便于理解的“傻瓜式”代码,不过度追求巧妙的设计,拒绝在代码中无意义地炫技。所以,if 嵌套的傻瓜式代码因为更加符合人类的思维顺序,往往更容易被理解(只要你弄清楚了代码嵌套的结构,上述代码案例因为其逻辑简单,我想你们也会有所感受)!

但是,不管怎么说,卫语句的使用都是利远大于弊的,这一点也被很多大公司所认可。

当然,也并不应该滥用卫语句,否则刚刚所述的卫语句弊端也会给你带来不小的麻烦!你应该根据你的代码需求进行更合理的代码设计,选择合适的处理方式,这一点非常重要!

三、参考资料

  1. 写出简洁代码:掌握卫语句,消除IF嵌套!
  2. Guard (computer science) - Wikimedia