2

我对clojure比较陌生,我正在寻找一种方法来使用一个所需键的值来验证另一个键。我可以通过使用这两个值创建另一个地图并传递它来做到这一点,但我希望有一种更简单的方法。谢谢

(s/def ::country string?)
(s/def ::postal-code   
  ;sudo-code
  ;(if (= ::country "Canda")
  ;(re-matches #"^[A-Z0-9]{5}$") 
  ;(re-matches #"^[0-9]{5}$"))
)

(s/def ::address
  (s/keys :req-un [
    ::country
    ::postal-code
    ::street
    ::state
  ]))
4

1 回答 1

1

这是一种方法multi-spec

(defmulti country :country)
(defmethod country "Canada" [_]
  (s/spec #(re-matches #"^[A-Z0-9]{5}$" (:postal-code %))))
(defmethod country :default [_]
  (s/spec #(re-matches #"^[0-9]{5}$" (:postal-code %))))

(s/def ::country string?)
(s/def ::postal-code string?)
(s/def ::address
  (s/merge
    (s/keys :req-un [::country ::postal-code])
    (s/multi-spec country :country)))

(s/explain ::address {:country "USA" :postal-code "A2345"})
;; val: {:country "USA", :postal-code "A2345"} fails spec: :sandbox.so/address at: ["USA"] predicate: (re-matches #"^[0-9]{5}$" (:postal-code %))
(s/explain ::address {:country "Canada" :postal-code "A2345"})
;; Success!

另一种选择是在您的规范中and添加另一个谓词:keys

(s/def ::address
  (s/and
    (s/keys :req-un [::country ::postal-code])
    #(case (:country %)
       "Canada" (re-matches #"^[A-Z0-9]{5}$" (:postal-code %))
       (re-matches #"^[0-9]{5}$" (:postal-code %)))))

您可能更喜欢这种multi-spec方法,因为它对扩展开放,即您可以defmethod为以后定义更多 s,country而不是将所有逻辑保留在and谓词中。

于 2018-05-05T10:44:32.647 回答