Clojure ';如果';使用多个表达式抛出NullPointerException

Clojure ';如果';使用多个表达式抛出NullPointerException,clojure,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 Nu

我对
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
时,它为什么会起作用呢?有更好的方法吗

关键部分是这个区块

((println "TRUE 1")
 (println "TRUE 2"))
这样做的目的是计算
println
s,将表达式转换为:

(nil nil)
然后,由于附加了括号,它尝试将
nil
作为函数调用,并将
nil
作为参数。由于
nil
不是一个函数,因此它抛出异常。它在第一种情况下起作用的原因是它有
let
来进行计算。由于
let
将对其主体中的每个表达式求值(并且不会尝试将结果视为函数),因此它的行为是正确的

如果要计算多个表达式,应使用

或者,由于没有“其他”部分,您可以使用


需要记住的重要一点是,在Clojure中,与C风格语言不同,您不能在表达式周围添加括号而不更改其含义。如果你用括号括起来(不加引号),它将尝试将其作为函数调用进行计算。

关键部分是这个块

((println "TRUE 1")
 (println "TRUE 2"))
这样做的目的是计算
println
s,将表达式转换为:

(nil nil)
然后,由于附加了括号,它尝试将
nil
作为函数调用,并将
nil
作为参数。由于
nil
不是一个函数,因此它抛出异常。它在第一种情况下起作用的原因是它有
let
来进行计算。由于
let
将对其主体中的每个表达式求值(并且不会尝试将结果视为函数),因此它的行为是正确的

如果要计算多个表达式,应使用

或者,由于没有“其他”部分,您可以使用


需要记住的重要一点是,在Clojure中,与C风格语言不同,您不能在表达式周围添加括号而不更改其含义。如果您将某个内容括在括号中(不加引号),它将尝试将其作为函数调用进行计算。

另请参阅:关于术语或发生的情况,有必要了解一些技术要点:第一个表达式不返回
“TRUE 1”
“TRUE 2”
;它打印它们,并返回
nil
。由于您在REPL中执行此操作,因此也会打印返回值:
“nil”
。那么,您可能会认为,在第二个表达式中,只返回了
NullPointerException
,但这并不完全正确。异常不是
if
表达式的值;这是个例外。它中断了表达式的计算。因为它没有被捕获,所以它被打印出来了。另请参见:关于术语的一些技术要点,或者关于发生了什么,值得弄清楚:第一个表达式没有返回
“TRUE 1”
“TRUE 2”
;它打印它们,并返回
nil
。由于您在REPL中执行此操作,因此也会打印返回值:
“nil”
。那么,您可能会认为,在第二个表达式中,只返回了
NullPointerException
,但这并不完全正确。异常不是
if
表达式的值;这是个例外。它中断了表达式的计算。因为没有被抓到,所以被打印出来了。现在有意义了。谢谢你可爱的解释。现在说得通了。谢谢你可爱的解释。