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

mid*_*doc 1 clojure

我对这种行为有点疑惑if.以下代码工作正常:

(if true 
  (let [x "whatever"]
    (println "TRUE 1")
    (println "TRUE 2")))
Run Code Online (Sandbox Code Playgroud)

收益:

TRUE 1
TRUE 2
nil
Run Code Online (Sandbox Code Playgroud)

但是如果let表达式被删除:

(if true 
  (
    (println "TRUE 1")
    (println "TRUE 2")))
Run Code Online (Sandbox Code Playgroud)

它还返回一个NullPointerException:

TRUE 1
TRUE 2
NullPointerException   user/eval8051 (NO_SOURCE_FILE:4)
Run Code Online (Sandbox Code Playgroud)

我怀疑是因为println回归了nil.但是,为什么它在let引入时会起作用?有一个更好的方法吗?

res*_*man 6

关键部分是这个块

((println "TRUE 1")
 (println "TRUE 2"))
Run Code Online (Sandbox Code Playgroud)

这样做是评估printlns,将表达式转化为:

(nil nil)
Run Code Online (Sandbox Code Playgroud)

然后,由于附加的括号,它尝试nil作为函数调用,nil作为参数.由于nil它不是一个函数,它会抛出异常.它在第一种情况下起作用的原因是因为它需要let进行评估.由于a let将评估其正文中的每个表达式(并且不会尝试将结果视为函数),因此它的行为正确.

如果要评估多个表达式,则应使用 do

(if true 
    (do (println "TRUE 1")
        (println "TRUE 2")))
Run Code Online (Sandbox Code Playgroud)

或者,因为没有"其他"部分,你可以使用 when

(when true
      (println "TRUE 1")
      (println "TRUE 2"))
Run Code Online (Sandbox Code Playgroud)

要记住的重要一点是,在Clojure中,与C风格的语言不同,你不能只在表达式周围添加括号而不改变含义.如果你在括号中包装一些东西(不引用它),它将尝试将其作为函数调用进行评估.