Боюсь, этот вариант использования является идеей Рича, а не моей, но, возможно, он будет интересен:
Сам язык использует эту функцию в def
формах (и удобной упаковке макросов def
включая defn
и defmacro
), поскольку метаданные, прикрепленные к символам, именующим создаваемые переменные, передаются самим переменным.Затем он может использоваться компилятором и различными инструментами.
Можно отметить, что defn
& Co. дополнительно может принимать аргумент карты атрибутов, который объединяется с метаданными Vars, поэтому используйте метаданные на символическом имени.не является необходимым с точки зрения пользователя.Обычный def
, однако, этого не делает, а внутри defn
расширяется до формы def
с метаданными, поступающими из карты атрибутов, прикрепленной к самому имени Var.(Ради полноты можно изменить карту метаданных Var на отдельном этапе после ее создания, но это не то, что происходит в defn
.)
Все это не скрыто от программиставообще, кстати.Напротив, прикрепление метаданных к символу «вручную» во многих случаях является более кратким, чем использование карты атрибутов (возможно, можно даже сказать идиоматичнее).Собственная стандартная библиотека Clojure использует этот стиль (и я имею в виду post-bootstrap) - например, clojure.core
и clojure.string
определяют Vars с именем replace
, но только последний помечен с типом возвращаемого значения (а именно String
):
;;; clojure.core
(defn replace
...)
;;; clojure.string
(defn ^String replace
...)
^String
здесь преобразуется в {:tag String}
, который присоединяется к символу replace
во время чтения и позже используется компилятором (как подсказка типа).Другие применения включают в себя пометку Vars как приватную с ^:private
(в Clojure 1.3, ^{:private true}
в 1.2), присоединение строк документации к Vars, созданным с помощью простого def
(единственный способ сделать это в 1.2; 1.3 позволяет использовать дополнительный аргумент docstring,но ^{:doc "..."}
все еще используется) и т. д.
Точно так же в ClojureScript у вас могут быть две функции с именем foo
, только одна из которых должна быть экспортирована (конечно, в разных пространствах имен).В этом случае вы скажете
(defn ^:export foo ...)
в одном пространстве имен и
(defn foo ...)
в другом;^:export
переводится в ^{:export true}
во время чтения, это объединяется с метаданными этого вхождения символа foo
, а затем читается и обрабатывается компилятором ClojureScript.