逗号运算符是类olor:#f60; text-decoration:underline;’ href=”https://www.php.cn/zt/16010.html” target=”_blank”>c语言(例如javascript和c++)中鲜为人知的运算符之一。本质上,它界定了一系列表达式并仅返回最后一个表达式的结果。
const a = 1; const b = 2; const c = 3; const result = (a, b, c, 4, 5, 6, true); console.log(result); // true
if (false, true) console.log('hello'); // hello
很自然地会问:什么时候将多个表达式塞进一行会有用?此外,即使它有用,为什么用逗号分隔的表达式序列(在单行)比分号分隔的语句序列(跨多行)更具可读性和可维护性?我们什么时候应该选择其中一种而不是另一种?
这些是我多年来一直努力回答的问题,但现在我想我终于有了答案。在本文中,我针对逗号运算符提出了一个令人信服的案例(坦率地说,也许是唯一的一个案例)。
一个激励人心的例子
我们先来说一下条件三元运算符。如下所示,如果条件为真,则评估值。否则,它评估另一个。这里强调关键字“评估”,因为分支仅在满足条件时执行。
const result = condition ? value : another;
在大多数情况下,它都是整洁漂亮的。然而,当我们需要在返回条件值之前在分支之间执行更复杂的逻辑时,它就会崩溃。此时,我们诉诸这种不幸的变态:
let result; // uninitialized! yikes! if (condition) { // do some complex stuff in between... dosomething(); // ... result = value; // actual assignment } else { // do other complex stuff in between... doanotherthing(); // ... result = another; // actual assignment } // hopefully we didn't forget to initialize `result`!
现在这个配方存在很多问题。
- 结果一开始是未初始化的。这本质上并不是邪恶的,但避免由于未定义而导致错误的一种简单且经过验证的方法是始终初始化变量。
- 结果的初始化实际上是在分支的底部——与其声明相分离。
- 在条件结束时,我们最好希望结果肯定已初始化。如果不是我们,我们最好希望我们的队友同样执行这一点。如果不是现在,我们最好希望未来的开发者也能坚持这一点!
如果我们坚持使用条件三元表达式,就有办法绕过这个限制。我们只需要将代码重构为函数即可。这绝对是说起来容易做起来难。这个噱头很快就过时了!
function computewrappedvalue() { // ... return value; } function computewrappedanother() { // ... return another; } // how cumbersome! const result = condition ? computewrappedvalue() : computewrappedanother();
基于表达式的编程语言(例如 rust)有更优雅的解决方案。通过将 if 语句 重新分类为 if 表达式 ,可以对每个分支进行求值,从而返回稍后可以存储在变量中的值。
// a conditional ternary operator thus looks like this. each branch // returns a value, which is captured by the `result` variable. // we thus ensure that `result` is always initialized by construction. let result = if condition { value } else { another };
// if we wanted to do something more complex, we use the same syntax. let result = if condition { do_something(); // in rust, the last expression without a semicolon is the value // that will be "returned" by the overall `if` expression. result } else { do_another_thing(); another };
我们可以用类似 c 的语言来模拟这个吗?你可能早就预见到了我的发展方向,但是可以!
一个令人信服的案例
我们想要的是一种在返回三元分支内的值之前任意执行语句的方法。好吧,对我们来说幸运的是,这正是逗号运算符的用途。
// parenthesized for clarity. const result = condition ? (dosomething(), value) // evaluates to `value` : (doanotherthing(), another); // evaluates to `another`
这个公式的巧妙之处在于,分支表达式仅在必要时才进行计算。我们有效地模拟基于表达式的编程语言的行为。临时包装函数的时代已经一去不复返了!
但是可惜,我们只能用这种技术走这么远。你可以想象,对于一些足够大的 n,将 n 条语句塞进一行已经需要重构到它自己的函数中。就我个人而言,到 > 3 时我已经重新考虑了。就可读性而言,任何高于此值的结构都是可疑的。
// maybe we should reconsider here? const result = condition ? (x++, thing = hello(), dosomething(), value) : (++y, thing = world(), doanotherthing(), another);
// Okay, stop. Definitely turn back now! const result = condition ? ( x++, thing = hello(), doSomething(), doMore(y), doEvenMore(thing), value, ) : ( ++y, thing = world(), doAnotherThing(), doMore(y), doEvenMore(thing), another, ); // Unless, of course, you're fine with this. It kinda does // look like a Rust `if` expression if you squint hard enough.
结论
总而言之,我们看到了逗号运算符的一个令人信服的案例:复杂的条件三元运算。当分支又短又甜时,逗号运算符会大放异彩,但在三个内联语句之后很快就会过时。到那时,可能会更好。
那么你应该使用逗号运算符吗?老实说……是的!可读的代码会考虑到下一个读者,因此只要逗号链不会太长,我就会接受甚至鼓励这种编码风格。如果我们考虑替代方案(即未初始化的变量和重构的微函数),逗号运算符毕竟没那么糟糕。
在实践中,我已经在自己的代码库中添加了这些看起来很有趣的逗号运算符。但公平地说,我很少需要多语句三元条件。但当我这样做时,我的腰带上就有了一个很酷的工具,可以简洁地表达我的意图。
为此,我对逗号运算符提出了令人信服的理由。
以上就是逗号运算符的一个令人信服的案例的详细内容,更多请关注php中文网其它相关文章!