以下表格
(let ((foo nil))
(ecase foo
(:bar 1)
(:baz 2)
(nil 3)))
Run Code Online (Sandbox Code Playgroud)
抛出错误NIL fell through ECASE expression
.解决方法似乎是nil
用括号括起案例,如下所示:
(let ((foo nil))
(ecase foo
(:bar 1)
(:baz 2)
((nil) 3))) ;; => 3
Run Code Online (Sandbox Code Playgroud)
但为什么第一个例子不起作用?打开的nil
案件有一些特殊含义吗?
每个子句case
可以匹配单个项目或项目列表,例如,您可以写:
(ecase foo
(:bar 1) ;; match a specific symbol
((:baz :quux) 2)) ;; match either of these symbols
Run Code Online (Sandbox Code Playgroud)
NIL
也是Lisp中的空列表,当它被用作测试时,case
它是如何处理的,因此它永远不会匹配任何东西.同样,T
并且OTHERWISE
用于指定默认情况,因此您无法将它们作为单个项目进行匹配.要匹配其中任何一个,您需要将它们放在一个列表中.
从技术上讲,规范说明了条款中的键:
keys ---对象列表的指示符.在大小写的情况下,符号
t
并otherwise
不能用作键指示符.要将这些符号自身称为键,必须分别使用指示符(t)
和(otherwise)
.
并且列表指示符的定义说:
对象列表的指示符; 也就是说,一个表示列表的对象,它是以下之一:非零原子(表示单元素列表,其元素是非零原子)或正确的列表(表示自身).
请注意,将单个原子视为单例列表的情况称为"非零原子".这允许NIL
属于第二种情况,其中适当的列表表示自己.否则,将无法为空列表创建列表指示符,因为NIL
这表示(NIL)
.
你可能会争辩说,有一个空的键列表没什么意义CASE
,因为它永远不会匹配任何东西,整个子句可以省略.这种退化的情况是为了自动代码生成(例如扩展到其他宏CASE
)的好处,因为它们可能产生空列表,并且这些应该与其他列表一致地处理.他们更难以使条款的生成取决于是否有任何键.