1

在下面的 case 语句中,x 被设置为 #\j,但返回了 "bye"。

(case (find #\j "joy") ((x) (princ "hi")) (otherwise (princ "bye")))

find 应该返回 #\j,它应该匹配 x,对吗?

4

2 回答 2

5

我们来看一下。

CL-USER 2 > (setf x #\j)
#\j

CL-USER 3 > (case (find #\j "joy") ((x) (princ "hi")) (otherwise (princ "bye")))
bye
"bye"

简化:让我们摆脱FIND.

CL-USER 4 > (case #\j ((x) (princ "hi")) (otherwise (princ "bye")))
bye
"bye"

不工作。简化:不要PRINC

CL-USER 5 > (case #\j ((x) (princ "hi")) (otherwise "bye"))
"bye"

不工作。简化:不要PRINC

CL-USER 6 > (case #\j ((x) "hi") (otherwise "bye"))
"bye"

不工作。我们有一个小表情。CASE是一个宏。让我们展开表格:

CL-USER 7 > (macroexpand '(case #\j ((x) "hi") (otherwise "bye")))
(LET ((#:G1084 #\j))
  (COND ((OR (EQL (QUOTE X) #:G1084)) "hi")
        (T "bye")))
T

哦,X是引用而不是评估。因此,您正在测试字符#\j是否等于符号X。这失败了。

CASE不评估密钥。

解决方案:要么使用类似的东西,COND要么编写一个隐藏类似COND. 这已经写了很多次作为练习。

CL-USER 8 > (let ((value (find #\j "joy")))
              (cond ((eql value x) "hi")
                    (t "bye")))
"hi"
于 2013-01-11T08:49:46.983 回答
3

不评估子句键,因此子句((x)...)将仅匹配符号x。这就是case的重点:键是常量,因此可以编译表单以生成更高效的代码。如果您想要动态键,请使用关联列表、哈希表等。

于 2013-01-11T07:04:39.157 回答