TL;DR

  • メタデータはオブジェクトの論理的な値とは直交するデータを指す。var はドキュメント、型情報、ソース情報を含むマップをメタデータとして持ち、meta で確認できる。
  • 独自のメタデータはメタデータリーダマクロ ^ で付ける。よく使う :tag には ^Classname という省略記法がある。

内容

Clojure におけるメタデータは、オブジェクトの論理的な値とは直交するデータを指す。たとえば、人を表すオブジェクトが XML へシリアライズできるかという情報は、人そのものとは直接関係がない。この「XML へシリアライズできるか」という情報がメタデータである。

var のメタデータ

Clojure 自身も、メタデータをいくつかの箇所で使っている。たとえば var は、ドキュメント・型情報・ソース情報を含んだマップをメタデータとして持っている。このメタデータは meta 関数で確認できる。

次は関数 str のメタデータである。

(meta #'str)
; {:added "1.0",
;  :ns #object[clojure.lang.Namespace 0x1a59db39 "clojure.core"],
;  :name str,
;  :file "clojure/core.clj",
;  :static true,
;  :column 1,
;  :line 546,
;  ...}

メタデータリーダマクロ

var に付くメタデータの多くは、Clojure のコンパイラが自動的に付加する。ただし、:tag は自動で生成されない。独自のキーと値のペアを var に追加したい場合、メタデータリーダマクロが使える。

^metadata form

たとえば、引数の文字列をすべて大文字に変換する簡単な関数 shout を考え、引数と戻り値がともに文字列であることを :tag で書く。

(defn ^{:tag String} shout [^{:tag String} s]
	(clojure.string/upper-case s))

shout のメタデータを確認すると、Clojure が :tag を付与していることが分かる。

(meta #'shout)
; {:tag java.lang.String,
;  :arglists ([s]),
;  :name shout,
;  ...}

:tag はとてもよく使われるので、^Classname という省略記法が用意されている。

(defn ^String shout [^String s] (clojure.string/upper-case s))

メタデータが混ざって関数定義が読みにくい場合、メタデータを一番後ろに置くこともできる。

(defn shout
  ([s] (clojure.string/upper-case s))
  {:tag String})

共通のメタデータ

メタデータで共通して使われるキーとその意味は次のとおり。

キー用途
:ns名前空間
:nameローカル名
:added追加されたバージョン
:fileソースファイル
:lineソース行
:columnソース列
:tag引数または戻り値の期待する型
:arglistsdoc で表示される引数の情報
:docdoc で表示されるドキュメント
:macroマクロの場合に true

キーワード