Spec {{instrument}} 不会在协议方法上工作。无效参数将被静默接受,不发生错误。协议变量包含在 {{(instrument)}} 的返回值中。
重现步骤
`
(require
'[clojure.spec :as s]
'[clojure.spec.test :as test])
(defprotocol P
(method [this arg]))
(defrecord R []
P
(method [this arg]
(str "R.method called with " (pr-str arg))))
(s/fdef method
:args (s/cat :this any?
:arg number?))
(defn wrapped [this arg]
(method this arg))
(s/fdef wrapped
:args (s/cat :this any?
:arg number?))
(test/instrument)
(println (method (->R) "not a number"))
(println (wrapped (->R) "not a number"))
`
此代码产生以下输出
R.method 调用的参数为 "not a number" clojure.lang.ExceptionInfo: 调用 #’user/wrapped 未遵循规范:在 [1] val: "not a number" 在 [:args :arg] 处失败:谓词:number? ...
可能的解决方案
- 为协议方法添加对 {{instrument}} 的支持
- 说明 {{instrument}} 不会在协议方法上工作,不要从 {{(instrument)}} 返回协议方法变量,如果协议方法变量包含在传递给 {{(instrument syms)}} 的符号中,则抛出异常
另请参阅
CLJ-1941 描述了另一种情况,其中 {{instrument}} 不会工作。这个问题是在(链接:http://dev.clojure.org/jira/browse/CLJ-1941?focusedCommentId=43084&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-43084 文本:评论)中确定的。
解决方法
可以通过将协议方法包装在普通函数中并对函数进行规范来实现避免此问题。这已经是常见的做法。