11.2 条件判断(DONE)

条件控制结构会在众多的选项中做选择。Emacs Lisp中包含5种条件表达式:if(和绝大多数其他语言中的类似);when和unless(这些为if的变体);cond(更通用的条件表达式);以及pcase(更通用的cond)。

[Special Form] if condition then-form else-forms...

if 会基于condition的求值结果,选择对then-form求值还是对else-forms求值。若condition的求值结果为non-nil,那么会对then-form求值,并将其求值结果返回。否则,将会依次对else-forms中的表达式进行求值,并返回其最后一个表达式的求值结果。(if的else部分被隐式实现了progn)

若condition求值为nil,并且未提供else-forms,那么返回nil。

if 是一个特殊表达式,其中没有被选择的分支将不会被求值。因此在下面这个例子里,true将不会被打印,因为print根本就不会被调用:

(if nil
    (print 'true)
    'very-false)
=>   very-falses

[Macro] when condition then-forms...

这是if的一个变体,该变体中不包含else-forms,但可以包含若干then-forms。

特别的,

(when condition a b c)

和下面完全等价

(if condition (progn a b c) nil)

[Macro] unless condition forms...

这是if的一个变体,该变体中不包含then-from:

(unless condition a b c)

和下面完全等价

(if condition nil
    a b c)

[Specila Form] cond clause...

cond会在任意数量的分支中做出选择。cond中每个clause都必须是一个列表。该列表的car部分为condition而余下的部分均为表达式体body-forms。也就是说,一个clause看起来像这样:

(condition body-forms...)

cond会依次尝试测试每个clause中的condition,直到某个condition求值为non-nil;然后cond会对对应clause的body-forms进行求值,并将其中最后一个表达式的求值结果作为整体的求值结果。任何余下的clause都会被忽略。

clause同样可以类似这样:

(condition)

此时若condition求值为non-nil,那么cond表达式会将该值作为结果返回。

若每个condition求值均为nil,也就是所有的clause测试都未通过,那么cond会返回nil。

下面这个例子中有4个clause,其中每个clause分别测试x是否是数字、字符串、缓冲区以及符号:

(cond ((numberp x) x)
      ((stringp x) x)
      ((bufferp x)
       (setq temporary-hack x)
       (buffer-name x))
      ((symbolp x) (symbol-value x)))

通常我们想在最后设置一个默认clause,当前面所有的clause都未通过测试时求值。此时我们可以将t作为该clause的condition,就像这样(t body-forms)。表达式t求值后得到t,永远通过测试,因此该clause永远不会失败。举个例子:

(setq a 5)
(cond ((eq a 'hack) 'foo)
      (t "default"))
=>  "default"

若a求值结果为hack,则返回foo,否则返回字符串"default"。

任何条件结构都可以使用cond或if组合出来。因此,使用哪一个仅仅是风格问题。比如下面两个就是等价的:

(if a b c)

(cond (a b) (t c))

最后更新于