【问题标题】:Issue with clojure macro returning map with java objectclojure 宏返回映射与 java 对象的问题
【发布时间】:2013-06-20 18:40:52
【问题描述】:

我对宏很陌生,所以我有一个基本问题,似乎与 Java 对象在 Clojure 代码中的表示方式有关。我有一个应该返回地图的宏:

(defmacro g []
  (let [m {:color :black}]
     `(identity ~m)))


user=> (g)
{:color :black}

但是,当我在地图中使用 java 对象时,事情变得很奇怪

(defmacro g []
  (let [m {:color java.awt.Color/BLACK}]
     `(identity ~m)))

 user=> (g)
 CompilerException java.lang.RuntimeException: Can't embed object in code, maybe
 print-dup not defined: java.awt.Color[r=0,g=0,b=0], compiling:(NO_SOURCE_PATH:1
 :1)

如果我将defmacro 更改为defn,输出如下所示:

user=> (g)
(clojure.core/identity {:color #<Color java.awt.Color[r=0,g=0,b=0]>})

所以我猜这种表示会让读者感到厌烦。有正确的方法吗?

【问题讨论】:

    标签: macros clojure clojure-java-interop


    【解决方案1】:

    有几种方法可以编写此代码,但让我印象深刻的一种适当的宏观方式是让它返回一个评估地图的表单,包括let

    user> (defmacro g []
              `(let [m# {:color java.awt.Color/BLACK}]
                     (identity m#)))
    #'user/g
    user> (g)
    {:color #<Color java.awt.Color[r=0,g=0,b=0]>}
    

    这允许从类中解析对象。

    【讨论】:

    • 这在对象被“解析”时不会改变,在命名空间的意义上:解析都是在读取时完成的,在定义宏的命名空间中。不同之处在于,宏生成的代码将BLACK 查找为运行时 java.awt.Color 类中的静态字段。
    【解决方案2】:

    当你的宏展开时会发生这种情况。

    (macroexpand '(g))
    ;=> (clojure.core/identity {:color #<Color java.awt.Color[r=0,g=0,b=0]>})
    

    注意 Java 对象为何不可读?

    【讨论】:

    • 我不确定编译器会在评估周期之间打印并重新读取表单吗?
    • 为什么会失败呢? (我很好奇。)错误消息提到可能没有为对象定义print-dup
    • 嗯,我为java.awt.Color 实现了print-dup,打印扩展宏时似乎没有使用它。
    猜你喜欢
    • 2011-12-16
    • 2018-05-30
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-29
    • 2019-06-16
    相关资源
    最近更新 更多