从REPL(Cloure 1.4.0)我试图使用source
宏来显示我的函数的定义 - 但它回复'未找到来源'
我可以在source
上使用source
这样(并且可以看到它使用source-fn
) - 但不确定为什么它不喜欢我的defn x[] "hello"
函数定义?
user=> (source source)
(defmacro source
"Prints the source code for the given symbol, if it can find it.
This requires that the symbol resolve to a Var defined in a
namespace for which the .clj is in the classpath.
Example: (source filter)"
[n]
`(println (or (source-fn '~n) (str "Source not found"))))
nil
user=> (defn x[] "hello")
#'user/x
user=> (source x)
Source not found
nil
user=>
答案 0 :(得分:6)
source
只能获取类路径中可用的源文件中定义的函数源。它不适用于在REPL中定义的函数。
更准确地说,source
通过查找由其参数命名的Var来工作,检查Var上的元数据映射是否包含源信息(所有内容都可以工作:file
和:line
需要密钥),查找元数据映射中指定的文件,打开文件(作为类路径上的资源),跳过多行,最后返回下一个表单后面的文本;有关详细信息,请参阅(source clojure.repl/source-fn)
。
因此,它适用于存储在Vars中的东西 - 比如函数和宏 - 在类路径中仍然存在的源文件的顶层定义。它不适用于未存储在Vars中的内容,也不适用于存储在Vars中的内容,这些Vars的类路径中不存在后备源。后一种情况可以通过AOT编译和在REPL中定义的东西来实现。
答案 1 :(得分:4)
source
使用函数元数据来查找定义函数的文件。然后它读取该文件以查找函数定义,将其转换为String并返回它。
简而言之,(源代码)正在做这样的事情
user> (-> (resolve 'source)
meta
:file)
"clojure/repl.clj"
repl中定义的函数的元数据不包含有效的源文件。
user=> (meta (resolve 'x))
{:arglists ([]), :ns #<Namespace user>, :name x, :column 1, :line 1, :file "NO_SOURCE_PATH"}
您可以在source-fn
功能中看到完整的工作原理。