2017-07-29 57 views

Odpowiedz

3

Z docstring:

zmieniać tagów jest używany podczas generowania zmieniać tagów wygenerowane wartości z pasujące do tagów. retag może być słowem kluczowym, przy którym klucz zostanie przypisany znacznikiem ekspedycyjnym lub fn wygenerowanej wartości i znacznikiem ekspedycyjnym , który powinien zwrócić odpowiednio zmienioną wartość.

Jeśli retag to słowo kluczowe (jak w spec guide example) multi-spec wewnętrznie tworzy funkcję here, który jest wykorzystywany w funkcji implementacji generatora. Na przykład, te dwie zgłoszeń wielo-spec są funkcjonalnie równoważne:

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

Przekazanie retagfunkcji nie wydaje się być bardzo przydatna opcja podanym przykładzie przewodnika, ale jest bardziej przydatne przy multi-spec za nieprzestrzeganie mapy. Na przykład, jeśli chcesz użyć multi-spec z s/cat np. spec argumenty funkcyjne:

(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 trwa dwa lub trzy argumenty, w zależności od pierwszego Arg. Jeśli staramy się multi-spec to naiwnie pomocą s/cat kluczowym/tag, to nie będzie działać:

(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 

To gdzie jest w stanie przekazać retag funkcja jest użyteczna:

(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

Dziękuję za wielki wyjaśnienie i przykłady! – OlegTheCat