我对if
的行为感到有些困惑。以下代码工作正常:
(if true
(let [x "whatever"]
(println "TRUE 1")
(println "TRUE 2")))
返回:
TRUE 1
TRUE 2
nil
但如果删除了let
表达式:
(if true
(
(println "TRUE 1")
(println "TRUE 2")))
它也会返回NullPointerException
:
TRUE 1
TRUE 2
NullPointerException user/eval8051 (NO_SOURCE_FILE:4)
我怀疑这是由于println
返回nil
。但是,为什么引入let
时它会起作用?有一个更好的方法吗?
答案 0 :(得分:6)
关键部分是这个块
((println "TRUE 1")
(println "TRUE 2"))
这样做是评估println
,将表达式转换为:
(nil nil)
然后,由于附加括号,它尝试将nil
作为函数调用,并以nil
作为参数。由于nil
不是函数,因此抛出异常。它在第一种情况下起作用的原因是因为它需要let
进行评估。由于let
将评估其正文中的每个表达式(并且不会尝试将结果视为函数),因此它的行为正确。
如果要评估多个表达式,则应使用do
(if true
(do (println "TRUE 1")
(println "TRUE 2")))
或者,由于没有“其他”部分,您可以使用when
(when true
(println "TRUE 1")
(println "TRUE 2"))
要记住的重要一点是,在Clojure中,与C风格的语言不同,你不能只是在不改变含义的情况下在表达式周围添加括号。如果你在括号中包装一些东西(不引用它),它将尝试将其作为函数调用进行评估。