【问题标题】:Using clojure protocol across multiple namespaces跨多个命名空间使用 clojure 协议
【发布时间】:2020-09-16 15:33:15
【问题描述】:

我目前正在以相同的协议作为基础实现多种类型,并希望减少为了使用它们而需要包含在命名空间中的文件数量。举个例子:

basetype.clj

(defprotocol Base
  (do-something [obj]))

(deftype Basetype [obj]
  ...
  Base
   (do-something [obj] something-something))

second_type.clj

(ns project.second-type
  (:use project.basetype))

(deftype DifferentType [obj]
  ...
  Base
   (do-something [obj] something-slightly-different))

我所做的是为Basetype 构建的所有内容也适用于DifferentType。但是,我想通过在命名空间中包含 second_type.clj 而不是同时包含两者来访问函数 do-something。有没有办法做到这一点?

【问题讨论】:

  • 您可以执行以下操作以从 second_type 重新导出 do-something:在 seond_type.clj 的末尾您是 (ns-unmap 'project.second-type 'do-something),然后是 (intern 'project.second-type 'do-something a/do-something)。然后这个 do-something 将被转入另一个需要第二种类型的命名空间
  • Clojure 甚至对实现继承的出现表示遗憾:消费者对协议进行操作,对具体类型不感兴趣。它们需要 basetype 并调用 defprotocol 在 basetype ns 中创建的普通函数。还有另一种理论,那都是无稽之谈。调用者应使用 Java 互操作点表示法 (.methodName obj),因此它们不需要基本类型 ns。但这是有风险的——你已经放弃了面向对象的 FP,并且失去了用你自己的 fns 包装 defprotocol 创建的 fns 的机会,这些 fns 可以进行更多的日志记录或类型检查。

标签: clojure namespaces protocols


【解决方案1】:

正如我在评论中提到的,您应该能够从任何命名空间重新导出任何值。

你可以像这样组成简单的函数:

(defn reexport [from-ns name]
  (ns-unmap *ns* name)
  (intern *ns* name @(ns-resolve from-ns name)))

(reexport 'project.basetype 'do-something)

或从给定的 ns 中重新导出所有值:

(defn reexport-all [from-ns]
  (run! (partial reexport from-ns) (map first (ns-publics from-ns))))

(reexport-all 'project.basetype)

在回复中:

user> (ns x)
nil

x> (defn f [v] (inc v))
#'x/f

x> (ns y)
nil

y> (user/reexport 'x 'f)
#'y/f

y> (in-ns 'user)
#namespace[user]

user> (y/f 10)
11

user> (in-ns 'y)
#namespace[y]

y> (defn f2 [v] (dec v))
#'y/f2

y> (ns z)
nil

z> (user/reexport-all 'y)
nil

z> (in-ns 'user)
#namespace[user]

user> (z/f 1)
2

user> (z/f2 1)
0

【讨论】:

    猜你喜欢
    • 2017-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多