为什么(零)的评价不同于((println“foo”))

时间:2013-02-15 22:32:51

标签: clojure

为什么下面最后两行的差异?评估异常从REPL粘贴。我正在使用Clojure 1.4

(println "foo") ;; evals to nil

(nil)  ;; CompilerException java.lang.IllegalArgumentException: Can't call nil
((println "foo")) ;; NullPointerException

1 个答案:

答案 0 :(得分:8)

一个是编译时异常;另一个是运行时异常。

(nil)的情况下,编译器看到您正在尝试对nil进行函数调用,并给出编译错误。

((println "foo"))的情况下,编译器不会尝试推断内部形式(println "foo")将返回的内容。总而言之,它知道它可以返回一个函数,因此在编译时不会进行检查。当println确实返回nil并且您尝试调用它时,会在运行时发生异常。

作为动态语言意味着您通常不会尝试在编译时检测变量的类型错误。

观察:

(.setDynamic #'println)

(binding [println 
           (fn [x] 
             (when (pos? (rand-int 2)) 
               (fn [] (print "bar\n"))))] 
  ((println "foo")))

将随机打印“bar”并返回nil,没有运行时异常或者不打印任何内容并抛出运行时NullPointerException。这里很明显这个设计的println没有静态返回类型供编译器检测。

但编译器仍然可以检测仅涉及值的类型错误。