在不同的命名空间调用相同的函数

时间:2014-04-05 17:36:02

标签: clojure clojurescript

我有名称空间foobar。两者都有函数hello

我尝试编写一个根据参数调用foo/hellobar/hello的函数。换句话说:

(defn say-hello [target-namespace]
  (if (= target-namespace "foo")
    (foo/hello)
    (bar/hello)

类似的东西,除了想象有15个名称空间,所以一个简单的if-else就不够了。最好以某种方式利用target-namespace并找出从中调用的函数。有没有办法做到这一点?

1 个答案:

答案 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"