通常字符串类的接口会有一个名为IsEmpty
(VCL)或者empty
(STL)的方法。这是很合理的特例,但使用这些方法的代码经常需要否定这个谓词,从而导致"视觉(甚至心理上的)负担"(感叹号在开括号后面不太明显)。例如,看看这个(简化的)代码:
/// format an optional time specification for output
std::string fmtTime(const std::string& start, const std::string& end)
{
std::string time;
if (!start.empty() || !end.empty()) {
if (!start.empty() && !end.empty()) {
time = "from "+start+" to "+end;
} else {
if (end.empty()) {
time = "since "+start;
} else {
time = "until "+end;
}
}
}
return time;
}
由于空情况需要跳过,因此它有四个否定。我经常观察到这种否定,甚至在设计界面时也是如此,虽然这不是一个大问题,但很烦人。我只希望支持编写易于理解和易于阅读的代码。我希望你能理解我的观点。
也许我只是被蒙住了双眼:你会如何解决上述问题?
编辑:在阅读了一些评论后,我认为有必要说明一下,原始代码使用了VCL的System::AnsiString
类。这个类提供了一个非常易读的IsEmpty
方法:
if (text.IsEmpty()) { /* ... */ } // read: if text is empty ...
如果未被否定:
if (!text.IsEmpty()) { /* ... */} // read: if not text is empty ...
...而不是如果文本不为空。我认为字面上的is
最好让读者自己想象,这样否定形式也可以很好地工作。好吧,也许不是一个普遍的问题...
!
字符更简洁吗?我建议使用本地变量来简化阅读否定表达式。bool hasStart = !start.empty();
然后逻辑就更容易阅读了:if (hasStart || hasEnd) { ...
- David Rodríguez - dribeasif
重构为正向的empty
测试,仍然可以消除最外层的if
。 - Potatoswatter!foo.empty()
,那么你就有了一个更大的问题。请看周围,这被广泛使用,每个人都很好地理解它。 - PlasmaHHnot
显然更难被忽视... - Wolfand
、not
和or
运算符,而不是使用同样易懂且更显眼的运算符&&
、||
和!
。可以这样理解:当人们使用语言形式时,整个布尔代码会变得不那么有结构性,因为只有单词没有标点符号,然后not
就不那么突出了。就像没有任何标点符号的长句子对于许多人来说阅读起来很困难,在世界上和可能存在的太空生物也是如此,这可能与标点符号的历史有关... - Sebastian Mach!(start.empty() && end.empty())
替换!start.empty() || !end.empty()
以及用!(start.empty() && end.empty())
替换!start.empty() && !end.empty()
。 - Simon Kuang