Clojure 为什么(nil)的评估与((println";foo";)不同

Clojure 为什么(nil)的评估与((println";foo";)不同,clojure,Clojure,为什么下面最后两行有差异?从REPL粘贴评估异常。我正在使用Clojure 1.4 (println "foo") ;; evals to nil (nil) ;; CompilerException java.lang.IllegalArgumentException: Can't call nil ((println "foo")) ;; NullPointerException 一个是编译时异常;另一个是运行时异常 在(nil)的情况下,编译器看到您正在尝试对nil进行函数调用,并给

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

(println "foo") ;; evals to nil

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

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

(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
没有编译器要检测的静态返回类型

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