可能有人没有注意过,大部分程序语言都是区分 语句(statement) 和 表达式(expression)的,二者的区别是,如果我们写了一条语句,我们是想要得到它的副作用(effect),如果我们写了一条表达式,我们是想要得到它的值(value)。比如:
int a = b + c;
这是一条语句,我们想要的是“赋值”给a
的副作用。其中 b + c
是表达式,我们想要的是 b + c
的值。对表达式支持良好(更时髦一些的说法可能应该是支持表达式是一等公民?)的语言可以写出非常好看的代码,比如在 Rust 里你可以写出类似这样的代码:
let remark = match(score) {
90..=100 => "A",
80..90 => "B",
60..80 => "C",
_ => "D"
};
match 是 Rust 中模式匹配,暂且我们就把它当做就是 C++ 中的 switch 吧。C++ 不支持 if 或者 switch 表达式,所以不出意外,同样的逻辑,一般我们会这样写:
std::string remark = "";
if (90 <= score && score <= 100) remark = "A";
else if (80 <= score && score < 90) remark = "B";
else if (60 <= score && score < 80) remark = "C";
else remark = "D";
你也许会说,这有什么问题,不过是多写了几行 remark = ...
。确实,但写法啰嗦只是缺点之一。如果我们想要 remark
不是变量,而是常量呢?我们没法直接声明 const std::string remark = ""
然后再给它赋值了。而 Rust 版本的可以做到,这就是表达式的优雅之处。
不过庆幸(还是说不幸?很多人说 C++ 越来越复杂)我们有现代的 C++,也可以写出优雅的代码。通过使用即时调用的 lambda 函数,我们也能模拟出一个复杂的 if 表达式,忘掉三目运算符吧:
#include <iostream>
int main(int argc, char *argv[]) {
int score = 90;
const std::string remark = [&]() { // 我们可以声明为 const 了。
if (90 <= score && score <= 100) return "A";
else if (80 <= score && score < 90) return "B";
else if (60 <= score && score < 80) return "C";
else return "D";
}(); // 注意最末尾的 (),我们立即执行了这个 lambda。
std::cout << "remark: " << remark << std::endl;
return 0;
}
“即用即抛” 的 lambda
有很多类似这样的妙用,让 C++ 仿佛支持了 if/switch 表达式。或许有人会说,这么写怎么有点像 JavaScript…
总结一下,对于简短的变量初始化,可以这样用,尤其是如果想要声明成 const 常量的话。因为本来就算用 if statement 我们也不一定会把它封成一个函数,对可读性并没有太大影响。其实我觉得是提高了可读性,因为没有了多次的赋值操作。当然,我们也必须要杜绝那种又臭又长的 lambda
,不能把 lambda
当成函数定义来用。