【问题标题】:'if' with multiple expressions throwing NullPointerException'if' 与多个表达式抛出 NullPointerException
【发布时间】:2015-11-10 15:27:38
【问题描述】:

我对@9​​87654322@ 的行为有点疑惑。以下代码工作正常:

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

【问题讨论】:

  • 关于术语或发生的事情的一些技术点值得弄清楚:第一个表达式不返回 "TRUE 1""TRUE 2";它打印它们,并返回nil。由于您在 REPL 中执行此操作,因此也会打印返回值:"nil" 会被打印。那么,您可能会认为,在第二个表达式中,只返回了NullPointerException,但这并不完全正确。例外不是if 表达式的值;这是一个例外。它中断了表达式的计算。由于没有捕获,所以打印出来了。

标签: clojure


【解决方案1】:

关键部分是这个块

((println "TRUE 1")
 (println "TRUE 2"))

它的作用是评估printlns,将表达式变成这样:

(nil nil)

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

如果你想计算多个表达式,你应该使用do

(if true 
    (do (println "TRUE 1")
        (println "TRUE 2")))

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

(when true
      (println "TRUE 1")
      (println "TRUE 2"))

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

【讨论】:

  • 现在说得通了。感谢您的精彩解释。
猜你喜欢
  • 2017-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-20
  • 2014-10-19
  • 1970-01-01
  • 2023-03-15
相关资源
最近更新 更多