메타데이터

메타데이터 (Metadata)

심볼과 컬렉션은 메타데이터(metadata)를 지원해요. 메타데이터란 심볼이나 컬렉션에 대한 데이터 맵이에요. 이 메타데이터 시스템은 데이터에 임의의 주석(annotation)을 달 수 있게 해 주며, 타입에 관한 정보를 컴파일러에 전달하는 데 쓰이기도 하지만 애플리케이션 개발자가 데이터 소스 주석이나 정책 등 다양한 목적으로도 사용할 수 있답니다.

메타데이터에 대해 꼭 이해해야 할 점은, 메타데이터는 객체의 값(value)의 일부로 간주되지 않는다는 거예요. 그래서 메타데이터는 동등성(equality)이나 해시 코드에는 영향을 주지 않아요. 메타데이터에서만 다른 두 객체는 동등하다고 판단돼요.

그렇다 해도 메타데이터와 객체의 관계 자체는 불변(immutable)이에요 — 메타데이터가 다른 객체는 서로 다른 객체랍니다. 그 결과로 지연 시퀀스(lazy sequence)에 메타데이터를 적용하면 시퀀스의 머리(head)가 실현(realize)되어, 두 객체가 같은 시퀀스를 공유할 수 있게 돼요.

출처: Clojure 공식 문서 - Metadata

본문

(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

논리적 참(logical true)으로 설정하면 객체를 출력할 때 그 메타데이터도 리더(reader)가 다시 읽을 수 있는 형태로 함께 출력돼요.

(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)

각각 네임스페이스/var/ref/에이전트/원자(atom)의 메타데이터를 변경하거나 재설정해요.

메타데이터 리더 (Metadata Reader)

with-meta 외에도 리더는 그 뒤에 오는 표현식에 읽기 시점(read-time)에 메타데이터를 적용하는 메타데이터 리더 수단을 제공해요.

컴파일러가 메서드 오버로드 선택에 메타데이터를 어떻게 사용하는지는 타입 힌트 (Type Hints)param-tags를 참고하세요.

더 알아보기