clojure - 在 clojure 宏中调用特殊形式 `set!`
问题描述
给定 Java 实例obj
和成员名称(字符串)"Foo"
和 map conf
,我正在尝试生成如下所示的 Clojure 代码:
(if (get conf "Foo")
(set! (.Foo obj) (get conf "foo")
obj)
而且,如果我知道这"SomeEnum"
是一个 Java 枚举名称,那么代码如下:
(if (get conf "SomeEnum")
(set! (.someEnum obj)(Enum/valueOf SomeEnum (get conf "SomeEnum")))
obj)
这是我想出的:
(defmacro set-java [obj conf obj-name]
`(if (get ~conf ~obj-name)
(set! (. ~obj ~(symbol obj-name)) (get ~conf ~obj-name))
~obj))
(defn lowercase-first [s]
(apply str (Character/toLowerCase (first s)) (rest s)))
(defmacro set-java-enum [obj conf obj-name]
`(if (get ~conf ~obj-name)
(set! (. ~obj ~(symbol (lowercase-first obj-name)))
(Enum/valueOf ~(symbol obj-name) (get ~conf ~obj-name)))
~obj))
测试macroexpand
似乎给出了正确的结果,但在尝试之后:
(defn ^Policy map->policy [conf]
(-> (Policy.)
(set-java-enum conf "CommitLevel")
(set-java conf "durableDelete")
(set-java conf "expiration")
(set-java conf "generation")
(set-java-enum conf "GenerationPolicy")
(set-java-enum conf "RecordExistsAction")
(set-java conf "respondAllOps")))
我得到了一个奇怪的无休止的反射警告循环。
- - 编辑 - -
在与它斗争了很长一段时间后,我放弃了线程(->
)并以:
(defmacro set-java [obj conf obj-name]
`(when (get ~conf ~obj-name)
(set! (. ~obj ~(symbol obj-name)) (get ~conf ~obj-name))))
(defn lowercase-first [s]
(apply str (Character/toLowerCase ^Character (first s)) (rest s)))
(defmacro set-java-enum [obj conf obj-name]
`(when (get ~conf ~obj-name)
(set! (. ~obj ~(symbol (lowercase-first obj-name)))
(Enum/valueOf ~(symbol obj-name) (get ~conf ~obj-name)))))
(defn map->write-policy [conf]
(let [wp (WritePolicy. (map->policy conf))]
(set-java-enum wp conf "CommitLevel")
(set-java wp conf "durableDelete")
;; more non threaded object manipulation
wp))
所以我仍然不确定反射警告无限循环是什么,但希望这也是少数,并且可以进一步改进。
解决方案
我认为这是由于您~obj
在每个宏中多次插值。你的“循环”实际上是无穷无尽的,还是只有 ~128 或 ~256 步长?
在任何情况下,针对该特定问题的修复(无论它是否是您描述的问题的根本原因)是将表单包装起来(let [obj# ~obj] ...)
,然后参考obj#
下面,因此该参数仅插入一次。
您也可以(应该!)这样做conf
,obj-name
但它们可能不会主动引起问题,至少使用您提供的使用代码。
推荐阅读
- openstack - 如何缩小 AutoScalingGroup 中的特定实例?
- python - 当我的玩家触地时,如何让我的空闲动画播放
- java - Java 远程 JMX 配置被忽略
- android - RecyclerView 未使用 XmlPullParse 中的列表进行更新
- google-sheets - Google 表格:VLOOKUP:命名范围 - 插入/移动列
- java - java - 如何在迭代时以恒定时间修改Java链表中的元素?
- gradle - 在多模块项目中发布 gradle ear 到 artifactory
- hyperledger-fabric - 超级账本结构智能合约是否支持多个 go 文件
- python - 图像未通过本地主机显示在 HTTP Web 文件中
- powershell - 调用 Jenkins API 时使用 Powershell 替代 curl