サーチ…


構文

  • ::は、名前空間限定キーワードの省略形です。例えば、私たちが名前空間にいるなら、user :: fooはuser / fooの短縮形です。
  • #:または# - マップ内のキーを名前空間で修飾するためのマップリテラル構文

備考

Clojure 仕様は、バージョン1.9で入手可能なclojure用の新しい仕様/コントラクトライブラリです。

仕様は、ドキュメント、データの検証、テスト用データの生成など、さまざまな方法で活用されています。

述部を仕様として使用する

どの述語関数も仕様として使用できます。ここに簡単な例があります:

(clojure.spec/valid? odd? 1)
;;=> true

(clojure.spec/valid? odd? 2)
;;=> false

valid?関数はspecと値をとり、値が仕様に準拠する場合はtrueを返し、そうでない場合はfalseを返します。

もう1つの興味深い述語はメンバーシップです:

(s/valid? #{:red :green :blue} :red) 
;;=> true

fdef:関数の仕様書を書く

次のような機能があるとします。

(defn nat-num-count [nums] (count (remove neg? nums)))

この関数の仕様を書くには、同じ名前の関数仕様を定義します。

(clojure.spec/fdef nat-num-count
        :args (s/cat :nums (s/coll-of number?))
        :ret integer?
        :fn #(<= (:ret %) (-> % :args :nums count)))

:argsは、引数名に対応するキーワードラベルとそれに対応するspecによって引数のシーケンスを記述するregex specをとる。 :argsが正規表現で指定するスペックは、関数に対して複数のアライメントをサポートすることを要求します。 :ret関数の戻り値の仕様を指定します。

:fn:args:ret間の関係を制約する仕様です。これは、test.checkを実行するときにプロパティとして使用されます。それは単一の引数で呼び出されます:二つのキー:: :args (関数への適合した引数)と:ret (関数の適合戻り値)を持つマップ。

仕様の登録

仕様として機能する述語に加えて、 clojure.spec/defを使用して仕様をグローバルに登録することができます。 defは、登録されているスペックがnamespace修飾キーワードで指定されていることを要求します。

(clojure.spec/def ::odd-nums odd?)
;;=> :user/odd-nums

(clojure.spec/valid? ::odd-nums 1)
;;=> true
(clojure.spec/valid? ::odd-nums 2)
;;=> false

一旦登録されると、仕様はClojureプログラムのどこでもグローバルに参照できます。

::odd-nums構文は、 :user/odd-nums省略形です。 user空間にいると仮定します。 ::は現在のネームスペースに先行するシンボルを修飾します。

述語を渡すのではなく、スペック名を渡すことができvalid?それと同じように動作します。

clojure.spec /と&clojure.spec /または

clojure.spec/andclojure.spec/or使用して、複数の仕様や述語を使用して、より複雑な仕様を作成することができます。

(clojure.spec/def ::pos-odd (clojure.spec/and odd? pos?))

(clojure.spec/valid? ::pos-odd 1)
;;=> true

(clojure.spec/valid? ::pos-odd -3)
;;=> false

or 1点の有意な差で、同様に動作します。 an or specを定義するときは、可能な各ブランチにキーワードを付ける必要があります。これは、エラーメッセージで失敗する特定のブランチを提供するために使用されます。

(clojure.spec/def ::big-or-small (clojure.spec/or :small #(< % 10) :big #(> % 100)))

(clojure.spec/valid? ::big-or-small 1)
;;=> true

(clojure.spec/valid? ::big-or-small 150)
;;=> true

(clojure.spec/valid? ::big-or-small 20)
;;=> false

orを使用して仕様を適合させる場合、適合する仕様が返されます。

(clojure.spec/conform ::big-or-small 5)
;; => [:small 5]

仕様の記録

あなたは次のようにレコードを指定することができます:

(clojure.spec/def ::name string?)
(clojure.spec/def ::age pos-int?)
(clojure.spec/def ::occupation string?)

(defrecord Person [name age occupation])

(clojure.spec/def ::person (clojure.spec/keys :req-un [::name ::age ::occupation]))

(clojure.spec/valid? ::person (->Person "john doe" 25 "programmer"))
;;=> true

(clojure.spec/valid? ::person (->Person "john doe" "25" "programmer"))
;;=> false

将来のある時点で、レコードの名前空間によるレコードキーの適格性確認のためのリーダー構文またはビルトインサポートが導入される可能性があります。このサポートはすでにマップに存在します。

地図の仕様

地図にはどのキーを表示するかを指定してマップを指定できます。

(clojure.spec/def ::name string?)
(clojure.spec/def ::age pos-int?)
(clojure.spec/def ::occupation string?)

(clojure.spec/def ::person (clojure.spec/keys :req [::name ::age ::occupation]))

(clojure.spec/valid? ::person {::name "john" ::age 25 ::occupation "programmer"})
;; => true

:reqはマップに存在する必要があるキーのベクトルです。次のような追加のオプションを指定することができます:opt 、オプションのキーのベクトル。

これまでの例では、名前のキーが名前空間で修飾されている必要があります。しかし、マップキーが不適格であることは一般的です。この場合、 clojure.specは次のものを提供します:reqと:optは、非修飾キーの対応:req-un:opt-unです。非修飾キーを使用した同じ例を次に示します。

(clojure.spec/def ::name string?)
(clojure.spec/def ::age pos-int?)
(clojure.spec/def ::occupation string?)

(clojure.spec/def ::person (clojure.spec/keys :req-un [::name ::age ::occupation]))

(clojure.spec/valid? ::person {:name "john" :age 25 :occupation "programmer"})
;; => true

:req-unベクトルで提供されている仕様が、まだ修飾されたものとしてどのように提供されているかに注目してください。 clojure.specは、値を順守しているときにマップ内の未修飾バージョンを自動的に確認します。

名前空間マップリテラル構文を使用すると、マップのすべてのキーを単一の名前空間で簡潔に修飾することができます。例えば:

(clojure.spec/def ::name string?)
(clojure.spec/def ::age pos-int?)
(clojure.spec/def ::occupation string?)

(clojure.spec/def ::person (clojure.spec/keys :req [::name ::age ::occupation]))

(clojure.spec/valid? ::person #:user{:name "john" :age 25 :occupation "programmer"})
;;=> true

特殊な#: reader構文に注目してください。これに続いて、すべてのマップキーを修飾する名前空間でこれを行います。これらは、提供された名前空間に対応する仕様と照合されます。

コレクション

コレクションにはさまざまな方法でコレクションを指定できます。 coll-ofはコレクションを指定し、いくつかの追加の制約を提供します。ここに簡単な例があります:

(clojure.spec/valid? (clojure.spec/coll-of int?) [1 2 3])
;; => true

(clojure.spec/valid? (clojure.spec/coll-of int?) '(1 2 3))
;; => true

制約オプションは、コレクションの主な仕様/述語に従います。コレクションの型を:kindように制限することができます:

(clojure.spec/valid? (clojure.spec/coll-of int? :kind vector?) [1 2 3])
;; => true

(clojure.spec/valid? (clojure.spec/coll-of int? :kind vector?) '(1 2 3))
;; => false

渡されたコレクションはベクトルではないため、上記はfalseです。

(clojure.spec/valid? (clojure.spec/coll-of int? :kind list?) '(1 2 3))
;; => true

(clojure.spec/valid? (clojure.spec/coll-of int? :kind set?) #{1 2 3})
;; => true

(clojure.spec/valid? (clojure.spec/coll-of int? :kind set?) #{1 "2" 3})
;; => false

上記の値は、セット内のすべての要素がintではないため、falseです。

いくつかの方法でコレクションのサイズを制限することもできます。

(clojure.spec/valid? (clojure.spec/coll-of int? :kind vector? :count 3) [1 2 3])
;; => true

    (clojure.spec/valid? (clojure.spec/coll-of int? :kind vector? :count 3) [1 2])
;; => false

(clojure.spec/valid? (clojure.spec/coll-of int? :min-count 3 :max-count 5) [1 2 3])
;; => true

    (clojure.spec/valid? (clojure.spec/coll-of int? :min-count 3 :max-count 5) [1 2])
;; => false

コレクション内の要素の一意性を強制することもでき:distinct

(clojure.spec/valid? (clojure.spec/coll-of int? :distinct true) [1 2])
;; => true

(clojure.spec/valid? (clojure.spec/coll-of int? :distinct true) [2 2])
;; => false

coll-ofは、シーケンス内のすべての要素coll-of確実にチェックされるようにします。大規模なコレクションの場合、これは非常に非効率的です。 every同じように動作coll-ofそれだけのサンプルを除いて、適合性からの配列要素の数が比較的少なく。これは大規模なコレクションでうまくいきます。ここに例があります:

(clojure.spec/valid? (clojure.spec/every int? :distinct true) [1 2 3 4 5])
;; => true

map-ofcoll-of map-ofと似ていますが、マップcoll-of場合は似ています。マップにはキーと値の両方があるので、キーの仕様と値の仕様の両方を指定する必要があります。

(clojure.spec/valid? (clojure.spec/map-of keyword? string?) {:red "red" :green "green"})
;; => true

coll-ofと同様coll-ofmap-ofはすべてのマップキー/値の適合map-ofチェックします。大きな地図の場合、これは非効率的です。同様coll-ofmap-of供給every-kv効率的に大規模なマップから値の比較的小さな数をサンプリングします:

(clojure.spec/valid? (clojure.spec/every-kv keyword? string?) {:red "red" :green "green"})
;; => true

シーケンス

specは任意の配列を記述して使用できます。これは、数多くの正規表現仕様演算を介してこれをサポートします。

(clojure.spec/valid? (clojure.spec/cat :text string? :int int?) ["test" 1])
;;=> true

catは、シーケンスを記述するために使用される各仕様のラベルが必要です。 catは、一連の要素とそれぞれの仕様を記述します。

altは、シーケンス内の特定の要素に対して可能な仕様の数から選択するために使用されます。例えば:

(clojure.spec/valid? (clojure.spec/cat :text-or-int (clojure.spec/alt :text string? :int int?)) ["test"])
;;=> true

altでは、各スペックにキーワードでラベルを付ける必要があります。

正規表現シーケンスは、任意の複雑なシーケンス記述仕様を作成するための非常に興味深く強力な方法で構成することができます。ここに少し複雑な例があります:

(clojure.spec/def ::complex-seq (clojure.spec/+ (clojure.spec/cat :num int? :foo-map (clojure.spec/map-of keyword? int?))))
(clojure.spec/valid? ::complex-seq [0 {:foo 3 :baz 1} 4 {:foo 4}])
;;=> true

ここで::complex-seqは、1つ以上の要素のシーケンスを検証します。最初の要素はintで、2番目の要素はキーワードからintのマップです。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow