Символы и коллекции поддерживают метаданные - дополнительные данные о символе или коллекции. Система метаданных позволяет произвольно аннотировать данные. Она используется для передачи компилятору информации о типах, но также может использоваться разработчиками приложений для многих целей, аннотирования источников данных, политики и т.д.
Важно понимать, что метаданные не считаются частью значения объекта. Поэтому метаданные не влияют на равенство (или хэш-коды). Два объекта, отличающиеся только метаданными, равны.
При этом метаданные и их связь с объектом неизменны - объект с другими метаданными является другим объектом. Одним из следствий этого является то, что применение метаданных к ленивой последовательности реализует голову последовательности, так что оба объекта могут использовать одну и ту же последовательность.
(_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) для применения метаданных к следующему за ним выражению во время чтения:
^{:doc "How it works!"}
- добавляет метаданные к следующему прочитанному значению.^:dynamic
- эквивалентно^{:dynamic true}
^^String
- эквивалентно^{:tag java.lang.String}
^"java.lang.String"
- эквивалентно^{:tag java.lang.String}
.
Ключ :tag
используется для подсказки типа объектов компилятору Clojure. Смотрите Java Interop: Type Hints для получения дополнительной информации и полного списка специальных подсказок типов.
Можно добавить несколько частей метаданных, соединяя макросы чтения метаданных в цепочку. Например: ^:dynamic ^ints obj
применит к объекту флаг :dynamic и подсказку типа int. Цепочки метаданных выстраиваются справа налево (левая имеет приоритет).
Обратите внимание, что макросы чтения метаданных применяются во время чтения, а не во время оценки, и могут использоваться только со значениями, поддерживающими метаданные, такими как символы, переменные, коллекции, последовательности, пространства имен, ссылки, атомы, агенты и т.д. Некоторые важные исключения, которые не поддерживают метаданные - это строки, числа, булевы значения, объекты Java, ключевые слова (они кэшируются и могут быть использованы совместно во время выполнения), и дефтипы (если они явно не реализуют clojure.lang.IMeta
).