使用Clojure协议实现自定义数据结构 [英] Implementing Custom Data Structures Using Clojure Protocols
问题描述
我可能错过了关于协议的全部知识,但是我的问题是,协议可以用来指示如何迭代自定义数据结构或println如何打印对象吗?
I may have missed the whole point about protocols but my question is, can protocols be used to dictate how to iterate a custom data structure or how println would print the object?
假设地图包含两个向量,
Assuming a map with two vectors,
{:a [] :b []}
第一次调用时,我想从:a向量中获取,但是当conj在此结构上时,我想将其链接到:b。我可以使用协议来实现这种行为吗?
When called first on it I would like to take from the :a vector but when conj on this structure i would like to conj to :b. Can I use protocols to achieve this type of behavior?
推荐答案
某些事情仍在Clojure中作为Java接口实现;其中,我想说一些可能会永远保持这种状态,以简化与其他JVM语言中的Clojure代码的协作。
Some things are still implemented as Java interfaces in Clojure; of those, I'd say some are likely to stay that way forever to ease cooperating with Clojure code from other JVM languages.
幸运的是,在使用<$定义类型时c $ c> deftype ,您可以让新类型实现所需的任何Java接口(Brian在上面的评论中提到)以及 java.lang的任何方法.Object
。匹配您的描述的示例可能看起来像这样:
Fortunately, when defining a type using deftype
, you can have the new type implement any Java interfaces you require (which Brian mentioned in a comment above), as well as any methods of java.lang.Object
. An example to match your description might look like this:
(deftype Foo [a b]
clojure.lang.IPersistentCollection
(seq [self] (if (seq a) self nil))
(cons [self o] (Foo. a (conj b o)))
(empty [self] (Foo. [] []))
(equiv
[self o]
(if (instance? Foo o)
(and (= a (.a o))
(= b (.b o)))
false))
clojure.lang.ISeq
(first [self] (first a))
(next [self] (next a))
(more [self] (rest a))
Object
(toString [self] (str "Foo of a: " a ", b: " b)))
在REPL上可以使用它的示例:
A sample of what you can do with it at the REPL:
user> (.toString (conj (conj (Foo. [] []) 1) 2))
"Foo of a: [], b: [1 2]"
user> (.toString (conj (conj (Foo. [:a :b] [0]) 1) 2))
"Foo of a: [:a :b], b: [0 1 2]"
user> (first (conj (conj (Foo. [:a :b] [0]) 1) 2))
:a
user> (Foo. [1 2 3] [:a :b :c])
(1 2 3)
请注意,REPL将其打印为序列;我相信这是因为 clojure.lang.ISeq
的内联实现。您可以跳过它,并使用自定义的<,用返回的(seq a)
代替一个 seq
方法,以打印表示形式返回。 code> toString 。但是, str
始终使用 toString
。
Note that the REPL prints it as a seq; I believe that's because of the inline implementation of clojure.lang.ISeq
. You could skip it and replace the seq
method with one returning (seq a)
for a printed representation using the custom toString
. str
always uses toString
, though.
如果需要 pr
族函数的自定义行为(包括 println
等),则必须考虑实现自定义打印方法
为您的类型。 打印方法
是在 clojure.core
中定义的多方法;看看Clojure的 core_print.clj 实现示例的来源。
If you need custom behaviour of pr
family functions (including println
etc.), you'll have to look into implementing a custom print-method
for your type. print-method
is a multimethod defined in clojure.core
; have a look at core_print.clj in Clojure's sources for example implementations.
这篇关于使用Clojure协议实现自定义数据结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!