可以接受原语和元数据的最简单的Clojure对象?
我想在Clojure中将元数据添加到字节数组中。因为这是不允许的,所以我想尝试的一个选项是最简单的对象包装器 下面是的源代码可以接受原语和元数据的最简单的Clojure对象?,clojure,metadata,Clojure,Metadata,我想在Clojure中将元数据添加到字节数组中。因为这是不允许的,所以我想尝试的一个选项是最简单的对象包装器 下面是的源代码 这让我开始看Clojure.lang.IObj。我还没有找到我想要的。以下是如何创建支持元数据的 (import '(java.io Writer)) (deftype Box [value _meta] clojure.lang.IObj (meta [_] _meta) (withMeta [_ m] (Box. value m)) clojure.
这让我开始看
Clojure.lang.IObj
。我还没有找到我想要的。以下是如何创建支持元数据的
(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)))
(导入(java.io编写器))
(定义类型框[值]
clojure.lang.IObj
(元
(带meta[m](框值m))
clojure.lang.IDeref
(deref[u]值)
对象
(toString[这个]
(str(.getName(该类))
": "
(pr str值)
(定义方法打印方法框[o,^w]
(.写w“#”))
(除霜盒
([值](框值为零))
([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}
user>(def盒装(框(->>(范围5))
(映射字节)
(字节数组)
{:stuff:foo})
#
用户>@已装箱
[0, 1, 2, 3, 4]
用户>(元框)
{:stuff:foo}
用户>(元(带有元框{:stuff:bar}))
{:stuff:bar}
这是我能想到的将元数据放在字节数组上的最简单方法(reify
不适用于clojure.lang.IObj
并且记录包含更多不相关的功能)
另一种选择(可能更简单,具体取决于上下文)是将字节数组存储在映射中,元数据要么放在映射旁边,要么作为实际元数据。在与一些人讨论了#clojure IRC之后,我编写了一个简单的Java类,
MetaBox
,它实现了clojure.lang.IObj
。您可以在Clojure中使用metabox/box
和metabox/val
以及常见的元数据功能,如meta
和with meta
,轻松使用此功能
(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)))
; [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}
您可以在上找到源代码和自述文件
更新:由于一些讨论和建议(见下文),截至,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}
你看过吗?@DaoWen是的,我看过。我正在树立一个榜样;如果它有任何承诺,我将与您分享。您是出于什么考虑而选择此而不是
deftype
?顺便说一句,由于没有前缀val
会对clojure.core/val
造成阴影,因此可能值得使用其他东西(value
或val of
可能?),实际上,clojure.lang.IDeref
可能是一种公开该值的好方法。我更新了我的示例代码,将其包括在内(并采用了术语box
)。jbm:我们刚刚讨论了IRC上的引用类型。这是一个有趣的想法,deref
/@
语法干净而诱人。然而,对于我的特定用例,引用类型有太多的细节。Clojure让他们管理状态和身份。我只需要不变性;我不需要也不希望装箱的值可以按照ref、agent或agent提供的方式进行设置或更改。我不想像延迟、未来或承诺那样延迟或转移计算。Deftype不创建引用类型——它本质上生成一个Java类(有关详细信息,请参阅)。代理、期货等与我的建议无关,只是它们碰巧通过IDeref
公开了各种功能。此外,虽然deftypes可以有可变字段(正如Java类可以),但默认情况下它们没有(我的示例也没有)。基本上,我认为你可能误解了“参考类型:)你所说的“参考类型”是什么意思?当然,对于“引用类型”的某些定义,实现IDeref
会使类型成为“引用类型”,但仅仅使用不同的函数去引用并不一定会使类型减少“引用类型”。是的,deftype
比手工编写Java类更紧凑。一些评论。Clojure将空元数据存储为nil
,而不是{}
。另外,实现toString
也不错。@DavidJames,我添加了简单的toString
和print方法
实现,并将默认元数据从{}
更改为nil
。