2017-05-23 7 views
1

は、テキストやリンクレイヤのポート番号については、以下の仕様を検討:私のor-specは、指定されたspecの1つに対してのみ有効ですか?

(require '[clojure.spec.alpha :as spec]) 

(spec/def ::text (spec/and string? not-empty)) 
(spec/valid? ::text "a")    ; => true 
(spec/valid? ::text "")     ; => false 
(spec/def ::port (spec/and pos-int? (partial > 65535))) 
(spec/valid? ::port 4)     ; => true 
(spec/valid? ::port 0)     ; => false 
(spec/def ::text-or-port (spec/or ::text ::port)) 
(spec/valid? ::text-or-port 5)   ; => true 
(spec/valid? ::text-or-port "hi")  ; => false 

それが唯一のポート番号ではなくテキストを受け入れ、いくつかの理由のために、なぜそれが可能でしょうか?

答えて

2

この問題を理解するための鍵は、documentationにあり、spec/conformを使用しています。

(#(or (string? %) (integer? %)) 5)  ; => true 
(#(or (string? %) (integer? %)) "")  ; => true 
(#(or (string? %) (integer? %)) :a)  ; => false 

むしろ、ラベル及びスペック/述語の対をとる:

(spec/conform ::text-or-port 5) 
; => [:user/text 5] 

問題は、clojure.spec.alpha/orが2つの引数を与えclojure.core/orにdissimmilarあるAPIが最初truthyいずれかを返していることです。そして、名前空間付きのキーワードでさえラベルとして受け入れられるので、OPに与えられた::text-or-portの仕様は、::portの要件をパスしたものと一致し、それにラベル::textを付けました。以下は一致させるための正しい仕様です:

(spec/def ::text-or-port (spec/or :text ::text 
            :port ::port)) 
(spec/valid? ::text-or-port "hi")  ; => true 
(spec/valid? ::text-or-port 10)   ; => true 
関連する問題