我有名称空间foo
和bar
。两者都有函数hello
。
我尝试编写一个根据参数调用foo/hello
或bar/hello
的函数。换句话说:
(defn say-hello [target-namespace]
(if (= target-namespace "foo")
(foo/hello)
(bar/hello)
类似的东西,除了想象有15个名称空间,所以一个简单的if-else就不够了。最好以某种方式利用target-namespace
并找出从中调用的函数。有没有办法做到这一点?
答案 0 :(得分:4)
您可以使用intern
在另一个命名空间中获取或创建var。
(intern ns name)
(intern ns name val)
在命名空间中查找或创建由符号名称命名的var ns(可以是符号或命名空间),设置其根绑定 如果提供,则为val。命名空间必须存在。 var将采用任何 名称符号中的元数据。返回var。
所以理论上你可以让你的功能做到这一点:
(defn say-hello [target-namespace]
((intern target-namespace 'hello)))
但是,这在Clojure / ClojureScript中是一件非常不寻常的事情,你可以使用其中一种多态方案(如协议或多方法)来解决问题。协议可以处理大多数用例,并且可能是您最好的起点(特别是如果您来自Java - 它们非常类似于接口)。
语法是这样的:
(defprotocol Friendly
(say-hello [this]))
您可以使用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"