2

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

(println "foo") ;; evals to nil

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

1 回答 1

8

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

(nil)编译器看到您正在尝试调用函数nil并给您一个编译错误的情况下。

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

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

观察:

(.setDynamic #'println)

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

它将随机打印 "bar" 并返回nil没有运行时异常或不打印任何内容并抛出 run-time NullPointerException。很明显,这个人为println的没有静态返回类型供编译器检测。

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

于 2013-02-15T22:46:19.830 回答