Ral*_*lph 24 macros clojure type-hinting
我正在尝试创建一个def带有类型提示的字符串Clojure宏:
(defmacro def-string [name value]
`(def ^String ~name ~value))
(def-string db-host-option "db-host")
Run Code Online (Sandbox Code Playgroud)
当我macroexpand这样,类型提示丢失:
(macroexpand '(def-string db-host-option "db-host"))
;=> (def db-host-option "db-host")
Run Code Online (Sandbox Code Playgroud)
别担心提示这种类型的智慧.
为什么宏会丢失元数据?如何编写此宏或任何包含元数据的宏?
kot*_*rak 35
^读者宏.defmacro从来没有看到它.提示被列入清单(unquote name).比较例如(meta ^String 'x)以(meta ' ^String x)看到效果.
你需要把提示放在符号上.
(defmacro def-string
[name value]
`(def ~(vary-meta name assoc :tag `String) ~value))
Run Code Online (Sandbox Code Playgroud)
用法:
user=> (def-string foo "bar")
#'user/foo
user=> (meta #'foo)
{:ns #<Namespace user>, :name foo, :file "NO_SOURCE_PATH", :line 5, :tag java.lang.String}
Run Code Online (Sandbox Code Playgroud)
元数据不会出现在宏扩展中,因为它应该是"不可见的".
如果宏是正确的(它不是),你应该能够调用(meta#'db-host-option)来检查var上的元数据.
请注意(def sym ...)在从符号接收的var上插入元数据.但是^ Tag~name在~name(unquote name)上设置元数据,而不是在绑定到name的传入符号上.它不能做任何其他事情,因为^ Tag ...处理由读取器完成,一旦宏扩展开始就已经完成.
你想要的东西
(defmacro def-string [name value]
`(def ~(with-meta name {:tag String}) ~value))
user> (def-string bar 1)
#'user/bar
user> (meta #'bar)
{:ns #<Namespace user>, :name bar, :file "NO_SOURCE_FILE", :line 1, :tag java.lang.String}
Run Code Online (Sandbox Code Playgroud)