最简单的可能接受原语和元数据的Clojure对象?

时间:2013-12-21 22:31:05

标签: clojure metadata

我想在Clojure中将元数据添加到字节数组中。由于这是不允许的,我想尝试的一个选项是可以工作的最简单的对象包装器。

以下是with-meta的源代码。

这让我开始关注Clojure.lang.IObj。我还没找到我想要的东西。

2 个答案:

答案 0 :(得分:5)

以下是如何创建支持元数据的deftype

(import '(java.io Writer))

(deftype Box [value _meta]
  clojure.lang.IObj
  (meta [_] _meta)
  (withMeta [_ m] (Box. value m))
  clojure.lang.IDeref
  (deref [_] value)
  Object
  (toString [this]
    (str (.getName (class this))
         ": "
         (pr-str value))))

(defmethod print-method Box [o, ^Writer w]
  (.write w "#<")
  (.write w (.getName (class o)))
  (.write w ": ")
  (.write w (-> o deref pr-str))
  (.write w ">"))

(defn box
  ([value] (box value nil))
  ([value meta] (Box. value meta)))

以下是一些示例用法:

user> (def boxed (box (->> (range 5)
                        (map byte)
                        (byte-array))
                      {:stuff :foo}))
#<Var@1acd39b: #<Box@c50aa1: #>>
user> @boxed
[0, 1, 2, 3, 4]
user> (meta boxed)
{:stuff :foo}
user> (meta (with-meta boxed {:stuff :bar}))
{:stuff :bar}

这是我可以想到的将元数据放在字节数组上的最简单方法(reify不能与clojure.lang.IObj一起使用,并且记录包含更多不相关的功能。)

另一个选项(可能更简单,取决于上下文)将字节数组存储在地图中,元数据可以与其一起或作为实际元数据。

答案 1 :(得分:1)

在与#clojure IRC的一些人讨论之后,我写了一个简单的Java类MetaBox,它实现了clojure.lang.IObj。您可以在Clojure中使用metabox/boxmetabox/val以及metawith-meta等常用元数据功能轻松使用此功能。

; [metabox "0.1.0"]
(require '[metabox.core :refer (box val)])
(def critical-density (box 0.692 {:uncertainty 0.01}))
(val critical-density) ; 0.692
(meta critical-density) ; {:uncertainty 0.01}

您可以在clj-metabox找到源代码和README。

更新:感谢一些讨论和建议(见下文),自version 0.2.0起,API使用deref代替val

; [metabox "0.2.0"]
(require '[metabox.core :refer (box)])
(def critical-density (box 0.692 {:uncertainty 0.01}))
@critical-density ; 0.692
(meta critical-density) ; {:uncertainty 0.01}