说我有以下Clojurescript代码:
(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实现这一目标?
one
和two
具有相同的“界面”。
PS我知道我可以将函数作为参数传递,但这无法回答问题。 (例如,命名空间可能具有许多功能,而我不想全部传递它们)
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会话中解析初始的名称空间,)
如果我离开了人为的示例,并在Clojurescript项目中尝试了此操作,则会得到以下跟踪信息:
#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)
答案 0 :(得分:3)
您可以使用ns-resolve函数在命名空间中查找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)