defn基本上定义为*:
(defmacro defn [name args & body]
`(def ~name (fn ~args ~@body)))
或者换句话说,你可以基本上写:
(defn my-func [a]
(stuff a))
作为*:
(def my-func
(fn [a] (stuff a)))
仅使用 fn 创建一个匿名函数,它不会单独绑定到外部的任何符号。它必须使用let 或def 绑定才能在其外部引用。
通过根据def 和fn 定义defn,将函数绑定到符号(以及随之而来的所有其他复杂性)和处理函数行为的职责可以分开。
当您为fn 提供名称时,它不能在函数外部引用,但可以用来引用自身以创建递归匿名函数:
(fn my-func [n] (my-func (inc n))
并且,它为函数提供了一个稍微好听的名称,以便显示在堆栈跟踪中以简化调试:
(defn my-func []
((fn my-inner-func [] (/ 1 0))))
=> #'digital-rain.core/my-func
(my-func)
java.lang.ArithmeticException: Divide by zero
at clojure.lang.Numbers.divide(Numbers.java:158)
at clojure.lang.Numbers.divide(Numbers.java:3808)
at digital_rain.core$my_func$my_inner_func__2320.invoke(form-init1838550899342340522.clj:2)
at digital_rain.core$my_func.invokeStatic(form-init1838550899342340522.clj:2)
at digital_rain.core$my_func.invoke(form-init1838550899342340522.clj:1)
*这些都是严重的轻描淡写和一点点误导,但它们简化了事情。
实际上,defn 不是使用 defmacro 定义的; defmacro 实际上是使用defn 定义的。 defn 还添加了一些好东西,例如前置/后置条件检查、文档和其他元信息;但这在这里并不重要。我建议查看它的source 以获得更深入的了解;虽然它很复杂。 clojure.core 的基本内容可能有点令人生畏。