将命名空间描述为参数



假设我有以下Clojudescript代码:

(ns one)
(defn foo [] 1)
(ns two)
(defn foo [] 2)
(ns other)
(defn thing [the-ns] (the-ns/foo))
; now I want to see 1
(other/thing one)
; now I want to see 2
(other/thing two)

我如何使用Clojurescript实现这一点?

CCD_ 1和CCD_;接口";。

附言:我知道我可以把函数作为参数传递,但这并不能回答问题。(例如,名称空间可能有很多函数,我不想全部传递(

已尝试ns-resolve

boot.user=> (ns one)
nil
one=> (defn foo [] 1)
#'one/foo
one=> (ns two)
nil
two=> (defn foo [] 2)
#'two/foo
two=> (ns other (:require [cljs.analyzer.api :as api]))
nil
other=> (defn thing [the-ns] (let [f (api/ns-resolve the-ns 'foo)] (f)))
#'other/thing
other=> (other/thing 'one)
java.lang.NullPointerException:
other=> (one/foo)
1
other=> (two/foo)
2

(是的,在java.lang.NullPointerException:之后没有跟踪,我继续显示REPL会话中解析的初始名称空间,(

如果我放弃这个人为的例子,在我的Clojudescript项目中尝试这个,我会得到这样的跟踪:

#object[Error Error: No protocol method IDeref.-deref defined for type null: ]
Error: No protocol method IDeref.-deref defined for type null:
at Object.cljs$core$missing_protocol [as missing_protocol] (http://0.0.0.0:8000/index.html.out/cljs/core.js:311:9)
at Object.cljs$core$_deref [as _deref] (http://0.0.0.0:8000/index.html.out/cljs/core.js:2164:17)
at cljs$core$deref (http://0.0.0.0:8000/index.html.out/cljs/core.js:4945:18)
at Function.cljs.analyzer.api.ns_resolve.cljs$core$IFn$_invoke$arity$3 (http://0.0.0.0:8000/index.html.out/cljs/analyzer/api.js:346:51)
at cljs$analyzer$api$ns_resolve (http://0.0.0.0:8000/index.html.out/cljs/analyzer/api.js:322:37)
at Function.cljs.analyzer.api.ns_resolve.cljs$core$IFn$_invoke$arity$2 (http://0.0.0.0:8000/index.html.out/cljs/analyzer/api.js:332:37)
at cljs$analyzer$api$ns_resolve (http://0.0.0.0:8000/index.html.out/cljs/analyzer/api.js:318:37)
at eval (eval at <anonymous> (http://0.0.0.0:8000/index.html.out/weasel/repl.js:30:495), <anonymous>:1:108)
at eval (eval at <anonymous> (http://0.0.0.0:8000/index.html.out/weasel/repl.js:30:495), <anonymous>:9:3)
at eval (eval at <anonymous> (http://0.0.0.0:8000/index.html.out/weasel/repl.js:30:495), <anonymous>:14:4)

您可以使用ns解析函数在命名空间中查找var。

(ns one)
(defn foo [] 1)
(ns two)
(defn foo [] 2)
(ns other)
(defn thing [the-ns] 
(let [f (ns-resolve the-ns 'foo)]
(f)))

(demo.other/thing 'one) ;; returns 1
(demo.other/thing 'two) ;; returns 2

但对于这种多态行为,使用协议或多种方法更为合适。

更新

上面的代码只在Clojure中工作,因为ns-resolve在ClojureScript中不存在。事实上,ClojureScript没有Vars。

但我们可以手动从名称空间对象中获取函数。我们还需要用导出元数据标记函数,以防止函数名称被"篡改":

(ns demo.one)
(defn ^:export foo [] 1)
(ns demo.two)
(defn ^:export foo [] 2)
(ns demo.other)
(defn thing [the-ns] 
(let [f (aget the-ns "foo")]
(f)))
(other/thing demo.one)
(other/thing demo.two)

最新更新