【问题标题】:How to share protocols between Clojure & ClojureScript如何在 Clojure 和 ClojureScript 之间共享协议
【发布时间】:2013-08-30 06:33:41
【问题描述】:

我在交叉命名空间中有一个协议:

(ns xxx.shared.interfaces)

(defprotocol ITimer
  (seconds [timer] "Return time in seconds since timer began"))

我有一个 Clojure 的实现:

(ns xxx.time
  (:require [xxx.shared.interfaces :refer [ITimer]]))

(defrecord Timer [start-nanos]
  ITimer
  (seconds [timer] (double (/ (- (System/nanoTime) (:start-nanos timer))
                              1000000000))))

问题是,当我在某些 Clojure 代码中使用此代码时,需要 xxx.time 命名空间和 :refer :all 它抱怨找不到 seconds

Unable to resolve symbol: seconds in this context

首先,这种方式可以共享协议吗?

其次,知道我如何才能做到这一点吗?

第三,这真的是进行这种代码共享的好方法吗?理想情况下,我也想分享记录,但它依赖于 Java 代码,所以我需要将其分解为一个函数。这样做会更好吗?

谢谢!

【问题讨论】:

    标签: clojure clojurescript


    【解决方案1】:

    seconds 定义在xxx.shared.interfaces 中,所以你需要:require / :use 才能调用它:

    (ns foo
      (:require [xxx.shared.interfaces :refer [seconds]]))
    
    ;; (seconds ...) will now work
    

    更详细地说,defprotocol 表达式创建了一个保存协议的 Var、JVM 端的底层 JVM 接口(在 ClojureScript 端没有与之对应的接口)和每个协议方法的 Var。然后可以像任何其他 Clojure 函数一样通过这些 Var 调用协议方法。

    当您为记录/类型实现协议时,就像您在 xxx.time 命名空间中所做的那样,如果您实际上不调用这些方法,您甚至不需要拉入这些变量(与提供实现)。类似地,一个需要调用协议方法但不太关心它调用它们的特定对象类型的命名空间只需要拉入协议定义的命名空间并使用相关的变量,而无需:require 任何实现的命名空间。

    【讨论】:

    • 至于代码共享问题,我想说共享任何作为共享代码工作的东西都很好,并且分解出特定于平台的协议方法实现无疑是使更多代码可共享的有效方法。是否值得可能取决于实际避免了多少重复。无论如何,如上所述,最初的问题与共享无关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-19
    • 1970-01-01
    • 2015-09-04
    • 2015-06-06
    • 1970-01-01
    • 2018-10-10
    相关资源
    最近更新 更多