麻烦显示实现IPersistentMap接口的类型

时间:2017-07-22 18:45:36

标签: clojure interface

我正在实现一个实际上只是哈希映射包装器的类型

(defn as-pairs [m]
  (when-not (empty? m)
    (seq (persistent! (reduce (fn [s [k vs]]
                                (reduce (fn [s v] (conj! s [k v])) s vs)) (transient []) m)))))


(deftype Rel [m]
  clojure.lang.Seqable
  (seq [this] (as-pairs m))
  clojure.lang.ILookup
  (valAt [this k] (get m k))
  (valAt [this k default] (get m k default))
  clojure.lang.IPersistentMap
  (assoc [this k v] (Rel. (update m k #(conj (or % #{}) v))))
  (assocEx [this k v] (throw (Exception.)))
  (without [this k] (Rel. (dissoc m k))))

(defn relation [] (Rel. (hash-map)))

它似乎按预期工作

state-machines.maps> (def r (relation))
#'state-machines.maps/r
state-machines.maps> (type r)
state_machines.maps.Rel
state-machines.maps> r
{} ; interesting that it actually displays a map! -- source of problem?
state-machines.maps> (type (assoc r :foo 1 :foo 2 :bar 1))
state_machines.maps.Rel
state-machines.maps> (get (assoc r :foo 1 :foo 2 :bar 1) :foo)
#{1 2}
state-machines.maps> (seq (assoc r :foo 1 :foo 2 :bar 1))
([:foo 1] [:foo 2] [:bar 1])
state-machines.maps> (assoc r :foo 1 :foo 2 :bar 1)
ClassCastException clojure.lang.PersistentVector cannot be cast to java.util.Map$Entry  clojure.core/key (core.clj:1518)
state-machines.maps> 

查看堆栈跟踪

1. Unhandled java.lang.ClassCastException
   clojure.lang.PersistentVector cannot be cast to java.util.Map$Entry

                  core.clj: 1518  clojure.core/key
            core_print.clj:  212  clojure.core/print-map/fn
            core_print.clj:   59  clojure.core/print-sequential
            core_print.clj:  208  clojure.core/print-map
            core_print.clj:  217  clojure.core/fn
            core_print.clj:  217  clojure.core/fn
              MultiFn.java:  233  clojure.lang.MultiFn/invoke
             pr_values.clj:   35  clojure.tools.nrepl.middleware.pr-values/pr-values/fn/reify
    interruptible_eval.clj:  113  clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn/fn
                  main.clj:  241  clojure.main/repl/read-eval-print
                  main.clj:  258  clojure.main/repl/fn
                  main.clj:  258  clojure.main/repl
                  main.clj:  174  clojure.main/repl
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  core.clj:  646  clojure.core/apply
                  core.clj:  641  clojure.core/apply
                regrow.clj:   18  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   87  clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  646  clojure.core/apply
                  core.clj: 1881  clojure.core/with-bindings*
                  core.clj: 1881  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   85  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   55  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  222  clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
    interruptible_eval.clj:  190  clojure.tools.nrepl.middleware.interruptible-eval/run-next/fn
                  AFn.java:   22  clojure.lang.AFn/run
   ThreadPoolExecutor.java: 1142  java.util.concurrent.ThreadPoolExecutor/runWorker
   ThreadPoolExecutor.java:  617  java.util.concurrent.ThreadPoolExecutor$Worker/run
               Thread.java:  745  java.lang.Thread/run

我假设其中一件事正在发生。

    core_print.clj:  212  clojure.core/print-map/fn
    core_print.clj:   59  clojure.core/print-sequential
    core_print.clj:  208  clojure.core/print-map

这是我需要实现的界面吗?

as-pairs更新为

(defn as-pairs [m]
  (when-not (empty? m)
    (seq (persistent! (reduce (fn [s [k vs]]
                                (reduce (fn [s v] (conj! s (clojure.lang.MapEntry/create k v))) s vs)) (transient []) m)))))

结果是:

state-machines.maps> (assoc (relation) :foo 1 :foo 2 :bar 1)
{:foo 1, :foo 2, :bar 1}

1 个答案:

答案 0 :(得分:2)

正如您所怀疑的那样,错误出现在print-map中,它在其参数上调用seq,然后在该序列的每个元素上调用keyval。正如错误消息所述,这两个函数期望它们的参数符合java.util.Map$Entry接口,并且Clojure向量不符合该接口。

解决方案是在[k v]函数中取as-pairs并将其替换为创建映射条目的表达式;有关详细信息,请参阅this question