2017-07-29 69 views

回答

3

从文档字符串:

重新标记被生成期间使用 匹配的标签重新标记生成的值。 retag可以是关键字,关键字是 调度标签将被关联,或者生成值fn和 调度标签,该标签应该返回适​​当的重新标记的值。

如果retag是一个关键字(如在spec guide example),multi-spec内部创建其在发电机执行功能中使用的功能here。例如,这两个多规格的声明在功能上等同:

(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)))) 

传递一个retag功能似乎并不像给导游的例子一个非常有用的选项,但使用multi-spec用于非时是比较有用地图。例如,如果您想要使用multi-specs/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?)) 

foo需要两个或三个参数,根据第一ARG。如果我们试图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 

这是能够传递一个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)) 
+0

感谢您的伟大解释和例子! – OlegTheCat