Clojure

メタデータ

シンボルとコレクションは、シンボルまたはコレクションに関するデータのマップであるメタデータに対応しています。メタデータシステムにより、データの任意の注釈付けが可能です。これはコンパイラに型に関する情報を伝えるために使用されますが、アプリケーション開発者はデータソース、ポリシーなどを注釈付けるために多くの目的に使用することもできます。

メタデータについて理解しておくべき重要な点は、それがオブジェクトの値の一部とは見なされないということです。そのため、メタデータは等価性(またはハッシュコード)に影響を与えません。メタデータだけが異なる2つのオブジェクトは等しいとみなされます。

ただし、メタデータとそのオブジェクトとの関係は不変です。メタデータが異なるオブジェクトは別のオブジェクトです。この結果として、遅延シーケンスにメタデータを追加すると、両方のオブジェクトが同じシーケンスを共有できるように、シーケンスの先頭が実現されます。


(meta obj)

objのメタデータを返します。メタデータがない場合はnilを返します。

(pprint (meta #'+)) ;; #'+ is the + var

;; {:added "1.2",
;;  :name +,
;;  :file "clojure/core.clj",
;;  :column 1,
;;  :line 984,
;;  :arglists ([] [x] [x y] [x y & more]),
;;  ...

(with-meta obj map)

objと同じ型と値のオブジェクトを、mapをそのメタデータとして返します。

(def m ^:hi [1 2 3])
(meta (with-meta m {:bye true}))
;; {:bye true}

*print-meta*

論理的にtrueに設定されている場合、オブジェクトを出力する際に、そのメタデータもリーダーで読み取ることができる形式で出力されます。

(def m ^:hi [1 2 3])
(binding [*print-meta* true]
  (prn m))

;; ^{:hi true} [1 2 3]

(vary-meta obj f & args)

objと同じ型と値のオブジェクトを、(apply f (meta obj) args)をそのメタデータとして返します。

(def m ^:hi [1 2 3])
(meta (vary-meta m merge {:bye true}))
;; {:hi true, :bye true}

(alter-meta! ref f & args) と (reset-meta! ref map)

それぞれ、名前空間/変数/ref/エージェント/アトムのメタデータを変更またはリセットします。

メタデータリーダーマクロ

with-metaに加えて、読み込み時にそれに続く式にメタデータを追加するためのいくつかのリーダーマクロ(リーダー:マクロ文字)があります。

  • ^{:doc "How it works!"} - 次に読み取られる値のメタデータにメタデータマップを追加します。

  • ^:dynamic - ^{:dynamic true}と同じです。

  • ^String - ^{:tag java.lang.String}と同じです。

  • ^"java.lang.String" - ^{:tag java.lang.String}と同じです。

:tagキーは、Clojureコンパイラにオブジェクトの型を示唆するために使用されます。詳細および特別な型ヒントの完全なリストについては、Javaとの相互運用:型ヒントを参照してください。

メタデータリーダーマクロを連結して、複数のメタデータを追加することができます。たとえば、^:dynamic ^ints objは、objに`:dynamic`フラグとints型ヒントの両方を適用します。メタデータは右から左へチェーンされます(左側のものが優先されます)。

メタデータリーダーマクロは評価時ではなく読み込み時に適用され、シンボル、変数、コレクション、シーケンス、名前空間、refs、アトム、エージェントなど、メタデータに対応する値でのみ使用できることに注意してください。メタデータに対応しない重要な例外は、文字列、数値、ブール値、Javaオブジェクト、キーワード(これらはキャッシュされ、ランタイム内で共有される可能性があります)、およびdeftype(clojure.lang.IMetaを明示的に実装する場合を除く)です。