Ole*_*Cat 8 clojure multimethod clojure.spec
您能用实例解释retag参数如何影响multi-spec创建?我觉得multi-spec文档难以消化.
从文档字符串:
在生成期间使用retag来使用匹配标记重新生成生成的值.retag可以是关键字,dispatch-tag将关联到哪个键,或者生成值和dispatch-tag的fn,它应返回适当重新标记的值.
如果retag是关键字(如规范指南示例中所示),则在此处multi-spec内部创建一个在生成器实现函数中使用的函数.例如,这两个多规范声明在功能上是等效的:
(s/def :event/event (s/multi-spec event-type :event/type))
(s/def :event/event (s/multi-spec event-type
(fn [genv tag]
(assoc genv :event/type tag))))
Run Code Online (Sandbox Code Playgroud)
考虑到指南的示例,传递retag 函数似乎不是一个非常有用的选项,但在multi-spec用于非地图时更有用.例如,如果你想使用multi-spec与s/cat如符合规范函数参数:
(defmulti foo first)
(defmethod foo :so/one [_]
(s/cat :typ #{:so/one} :num number?))
(defmethod foo :so/range [_]
(s/cat :typ #{:so/range} :lo number? :hi number?))
Run Code Online (Sandbox Code Playgroud)
foo取决于第一个arg,取两个或三个args.如果我们multi-spec使用s/cat关键字/标签尝试这种天真,它将无法工作:
(s/def :so/foo (s/multi-spec foo :typ))
(sgen/sample (s/gen :so/foo))
;; ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.Associative
Run Code Online (Sandbox Code Playgroud)
这是能够传递retag函数的地方很有用:
(s/def :so/foo (s/multi-spec foo (fn [genv _tag] genv)))
(sgen/sample (s/gen :so/foo))
;=>
;((:so/one -0.5)
; (:so/one -0.5)
; (:so/range -1 -2.0)
; (:so/one -1)
; (:so/one 2.0)
; (:so/range 1.875 -4)
; (:so/one -1)
; (:so/one 2.0)
; (:so/range 0 3)
; (:so/one 0.8125))
Run Code Online (Sandbox Code Playgroud)