如何在Clojure和ClojureScript之间共享协议

Gra*_*ald 2 clojure clojurescript

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

(ns xxx.shared.interfaces)

(defprotocol ITimer
  (seconds [timer] "Return time in seconds since timer began"))
Run Code Online (Sandbox Code Playgroud)

我有一个Clojure的实现:

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

(defrecord Timer [start-nanos]
  ITimer
  (seconds [timer] (double (/ (- (System/nanoTime) (:start-nanos timer))
                              1000000000))))
Run Code Online (Sandbox Code Playgroud)

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

Unable to resolve symbol: seconds in this context
Run Code Online (Sandbox Code Playgroud)

首先,是否有可能以这种方式共享协议?

其次,任何想法如何使这项工作?

第三,这实际上是一种很好的方式来进行这种代码共享吗?理想情况下我也想分享记录,但它依赖于Java代码,所以我需要将其分解为一个函数.这会是一个更好的方法来解决这个问题吗?

谢谢!

Mic*_*zyk 6

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

(ns foo
  (:require [xxx.shared.interfaces :refer [seconds]]))

;; (seconds ...) will now work
Run Code Online (Sandbox Code Playgroud)

详细说明,defprotocol表达式创建一个包含协议的Var,一个JVM端的底层JVM接口(在ClojureScript端没有这个接口)和每个协议方法的Var.然后可以通过这些Vars调用协议方法,就像任何其他Clojure函数一样.

实现记录/类型的协议时,就像在xxx.time命名空间中一样,如果实际上没有调用方法,则甚至不需要引入这些Vars(提供实现的另一个问题).类似地,需要调用协议方法但不太关心它调用它们的特定类型对象的命名空间只需要引入协议定义命名空间并使用相关的Vars而不需要:require任何实现名称空间.

  • 至于代码共享问题,我说可以分享任何作为共享代码的工作并且分解协议方法的特定于平台的实现肯定是使更多代码可共享的有效方法.它是否值得,可能取决于实际避免多少重复.在任何情况下,如上所述,原始问题与共享无关. (2认同)