Dep*_*sio 1 clojure clojurescript
我有命名空间foo和bar. 两者都有功能hello。
我正在尝试编写一个基于参数调用foo/hello或 的函数。bar/hello换句话说:
(defn say-hello [target-namespace]
(if (= target-namespace "foo")
(foo/hello)
(bar/hello)
Run Code Online (Sandbox Code Playgroud)
类似的事情,只是假设有 15 个命名空间,所以简单的 if-else 是不够的。最好以某种方式利用target-namespace并找出从中调用的函数。有没有好的方法可以做到这一点?
您可以使用intern在另一个命名空间中获取或创建 var。
(intern ns name)
(intern ns name val)
Run Code Online (Sandbox Code Playgroud)
查找或创建一个由命名空间 ns 中的符号名称(可以是符号或命名空间)命名的 var,如果提供,则将其根绑定设置为 val。命名空间必须存在。var 将采用名称符号中的任何元数据。返回变量。
所以理论上你可以让你的函数这样做:
(defn say-hello [target-namespace]
((intern target-namespace 'hello)))
Run Code Online (Sandbox Code Playgroud)
然而,这在 Clojure/ClojureScript 中是一件非常不寻常的事情,您可能可以使用协议或多方法等多态性选项之一更惯用地解决您的问题。协议可以处理大多数用例,并且可能是您最好的起点(特别是如果您来自 Java - 它们非常类似于接口)。
语法是这样的:
(defprotocol Friendly
(say-hello [this]))
Run Code Online (Sandbox Code Playgroud)
并且您可以使用 来创建许多符合协议的数据类型defrecord。
(defrecord person [name]
Friendly
(say-hello [this] (println (format "Hi, I'm %s" name)))
(defrecord dog [name]
Friendly
(say-hello [this] (println (format "Woof, Woof! I'm %s" name)))
(say-hello (Person. "Bob"))
;=> "Hi, I'm Bob"
Run Code Online (Sandbox Code Playgroud)