Метаданные

Символы и коллекции поддерживают метаданные - дополнительные данные о символе или коллекции. Система метаданных позволяет произвольно аннотировать данные. Она используется для передачи компилятору информации о типах, но также может использоваться разработчиками приложений для многих целей, аннотирования источников данных, политики и т.д.

Важно понимать, что метаданные не считаются частью значения объекта. Поэтому метаданные не влияют на равенство (или хэш-коды). Два объекта, отличающиеся только метаданными, равны.

При этом метаданные и их связь с объектом неизменны - объект с другими метаданными является другим объектом. Одним из следствий этого является то, что применение метаданных к ленивой последовательности реализует голову последовательности, так что оба объекта могут использовать одну и ту же последовательность.

(_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) and (_reset-meta!_ ref map)

Изменяют или сбрасывают метаданные соответственно для пространств имен, ссылок, атомов, агентов

Макросы для чтения метаданных

В дополнение к with-meta существует ряд макросов для чтения (The Reader: Macro Characters) для применения метаданных к следующему за ним выражению во время чтения:

Ключ :tag используется для подсказки типа объектов компилятору Clojure. Смотрите Java Interop: Type Hints для получения дополнительной информации и полного списка специальных подсказок типов.

Можно добавить несколько частей метаданных, соединяя макросы чтения метаданных в цепочку. Например: ^:dynamic ^ints obj применит к объекту флаг :dynamic и подсказку типа int. Цепочки метаданных выстраиваются справа налево (левая имеет приоритет).

Обратите внимание, что макросы чтения метаданных применяются во время чтения, а не во время оценки, и могут использоваться только со значениями, поддерживающими метаданные, такими как символы, переменные, коллекции, последовательности, пространства имен, ссылки, атомы, агенты и т.д. Некоторые важные исключения, которые не поддерживают метаданные - это строки, числа, булевы значения, объекты Java, ключевые слова (они кэшируются и могут быть использованы совместно во время выполнения), и дефтипы (если они явно не реализуют clojure.lang.IMeta).