短路求值(Short-circuit evaluation)

短路求值

Short-circuit evaluation

最早是在php中接触到的这种求值,后来在学习Lisp中又一次接触到了,于是想写一篇文章记录一下,并分享一下,这个被我忽略的可能可以说是细节的点吧

什么是短路求值(Short-circuit evaluation)

以下摘自Short-circuit evaluation

Short-circuit evaluation, minimal evaluation, or McCarthy evaluation (after John McCarthy) is the semantics of some Boolean operators in some programming languages in which the second argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression: when the first argument of the AND function evaluates to false, the overall value must be false; and when the first argument of the OR function
evaluates to true, the overall value must be true.

概况来说就是在求布尔表达式的时候程序并不会执行全部的Expression

比如AND或者OR操作时如果后面第一个 Expression 为 True,那么之后的 Expression 就不会再求值了。

一些例子

普通的C程序

1
2
3
4
5
int denom = 0;
if (denom != 0 && num / denom)
{
... // ensures that calculating num/denom never results in divide-by-zero error
}

使用了短路求值的C程序

1
2
3
4
5
int a = 0;
if (a != 0 && myfunc(b))
{
do_something();
}

在这个例子中 && 后的 myfunc(b) 将永远不会执行,因为 a!=0 永远是 FALSE
利用短路求值有 2 个有用的技巧

  1. 如果条件判断的 expression 需要复杂的计算,并且第一个结果为 False ,则可以不计算之后的表达式
  2. 可以构造一个 expression 来使第二个可能会发生运行时错误的 expression 成功运行
1
2
3
4
5
6
7
8
9
bool is_first_char_valid_alpha_unsafe(const char *p)
{
return isalpha(p[0]); // SEGFAULT highly possible with p == NULL
}

bool is_first_char_valid_alpha(const char *p)
{
return p != NULL && isalpha(p[0]); // 1) no unneeded isalpha() execution with p == NULL, 2) no SEGFAULT risk
}

这个例子避免了空指针

最近学习的 Lisp 中的例子:

1
2
3
(defparameter *is-it-even* nil)
(or (oddp 5)
(setf *is-it-even* t))

利用短路求值,用OR实现了条件判断

可能的问题:

尽管有上面说的优点,但是可能会带来没有意识到的问题,比如:

1
2
3
if (expressionA && myfunc(b)) {
do_something();
}

expressionATrue时无论**do_something()**是否执行,**myfunc(b)**都会执行,例如分配系统资源的操作。

相反,expressionAFalse时**myfunc(b)**永远不会执行

支持的语言

并不是所有语言和所有操作符支持的
Java 支持非短路求值也支持短路求值

常见的语言 支持的操作符
C, Obejective-C, C++, C# &&, ∥, ?
Java, MATLAB, R, Swift &&, ∥
JavaScript, GO, Haskel &&, ∥
Lisp, Lua, Scheme and, or
PHP &&, and, ∥, or
Python and, or
Visual Basic 不支持