使用Clojure协议实现自定义数据结构 [英] Implementing Custom Data Structures Using Clojure Protocols

查看:77
本文介绍了使用Clojure协议实现自定义数据结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可能错过了关于协议的全部知识,但是我的问题是,协议可以用来指示如何迭代自定义数据结构或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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆