我在交叉命名空间中有一个协议:
(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代码,所以我需要将其分解为一个函数。这会是一个更好的方法吗?
谢谢!
答案 0 :(得分:6)
seconds
在xxx.shared.interfaces
中定义,因此您需要:require
/ :use
才能调用它:
(ns foo
(:require [xxx.shared.interfaces :refer [seconds]]))
;; (seconds ...) will now work
详细说明,defprotocol
表达式创建一个包含协议的Var,一个JVM端的底层JVM接口(在ClojureScript端没有这个接口)和每个协议方法的Var。然后可以通过这些Vars调用协议方法,就像任何其他Clojure函数一样。
当您为xxx.time
命名空间实现记录/类型的协议时,如果您实际上没有调用方法,则甚至不需要引入这些Vars(另一个问题)从提供实施)。类似地,需要调用协议方法但不太关心它调用它们的特定类型对象的命名空间只需要引入协议定义命名空间并使用相关的Vars而不需要:require
任何实现名称空间。