将别名命名空间动态加载到另一个 Clojure 命名空间
Dynamically loading an aliased namespace to another Clojure namespace
我正在尝试在运行时从文件加载命名空间。对于这个命名空间,我希望有一个通用别名,这样我就可以使用独立于加载文件的实际命名空间的统一限定名称访问该命名空间中的函数。
示例(无效):
;; bar_a.clj
(ns bar-a)
(defn hello-world [] "hello world a")
;; bar_b.clj
(ns bar-b)
(defn hello-world [] "hello world b")
;; foo.clj
(ns foo)
(defn init [ns-name]
(let [ns-symbol (symbol ns-name)]
(require `[ns-symbol :as bar])
(bar/hello-world))) ;; => No such var bar/hello world
;; during runtime when calling `init`!!!
我已经尝试了各种方法(load-file
、load
)并将 require
移动到不同的地方。到目前为止运气不好。
我怎样才能做到这一点?
我认为问题在于符号的编译时解析不适用于动态加载的名称空间。在您的示例中, bar/hello-world
是在编译时解析的,但是在调用函数时需要动态完成。我不知道对此有更好的解决方案,但你可以尝试这样的事情:
(ns foo)
(defn init [ns-name]
(require (symbol ns-name))
(let [bar (find-ns (symbol ns-name))]
((ns-resolve bar 'hello-world))))
这当然不是很有效,因为每次调用该函数时都会解析命名空间和函数符号。不过你应该能明白。
我正在尝试在运行时从文件加载命名空间。对于这个命名空间,我希望有一个通用别名,这样我就可以使用独立于加载文件的实际命名空间的统一限定名称访问该命名空间中的函数。
示例(无效):
;; bar_a.clj
(ns bar-a)
(defn hello-world [] "hello world a")
;; bar_b.clj
(ns bar-b)
(defn hello-world [] "hello world b")
;; foo.clj
(ns foo)
(defn init [ns-name]
(let [ns-symbol (symbol ns-name)]
(require `[ns-symbol :as bar])
(bar/hello-world))) ;; => No such var bar/hello world
;; during runtime when calling `init`!!!
我已经尝试了各种方法(load-file
、load
)并将 require
移动到不同的地方。到目前为止运气不好。
我怎样才能做到这一点?
我认为问题在于符号的编译时解析不适用于动态加载的名称空间。在您的示例中, bar/hello-world
是在编译时解析的,但是在调用函数时需要动态完成。我不知道对此有更好的解决方案,但你可以尝试这样的事情:
(ns foo)
(defn init [ns-name]
(require (symbol ns-name))
(let [bar (find-ns (symbol ns-name))]
((ns-resolve bar 'hello-world))))
这当然不是很有效,因为每次调用该函数时都会解析命名空间和函数符号。不过你应该能明白。