'if'有多个表达式抛出NullPointerException

时间:2015-11-10 15:27:39

标签: clojure

我对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时它会起作用?有一个更好的方法吗?

1 个答案:

答案 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风格的语言不同,你不能只是在不改变含义的情况下在表达式周围添加括号。如果你在括号中包装一些东西(不引用它),它将尝试将其作为函数调用进行评估。