clojure - 在 deftype 中使用原子时出现奇怪的错误

标签 clojure

我有以下代码,定义了一个其中包含原子的类型。

(defprotocol IDeck
  (vec-* [dk] "Output to a persistent vector")
  (count-* [dk] "Number of elements in the deck")
  (conj1-*  [dk & es] "Adding multiple elements to the deck"))


(deftype ADeck [#^clojure.lang.Atom val]
  IDeck
  (vec-* [dk] (->> (.val dk) deref (map deref) vec))

  (count-* [dk] (-> (.val dk) deref count))

  (conj1-* [dk & es]
    (try
      (loop [esi es]
        (let [e (first esi)]
          (cond
            (nil? e) dk
            :else
            (do
              (swap! (.val dk) #(conj % (atom e)))
              (recur (rest esi))))))
      (catch Throwable t (println t)))))

(defn new-*adeck
  ([] (ADeck. (atom [])))
  ([v] (ADeck. (atom (vec (map atom v))))))

(defn conj2-* [dk & es]
  (try
    (loop [esi es]
      (let [e (first esi)]
        (cond
          (nil? e) dk
          :else
          (do
            (swap! (.val dk) #(conj % (atom e)))
            (recur (rest esi))))))
    (catch Throwable t (println t))))


;; Usage 
(def a (new-*adeck [1 2 3 4]))

(count-* a)
;=> 4

(vec-* a)
;=> [1 2 3 4]

(conj1-* a 1 2)  ;; The deftype case
;=> IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long

(vec-* a)
;=> [1 2 3 4]

(conj2-* a 1 2) ;; The defn case
(vec-* a)
;=> [1 2 3 4 1 2]

尽管两个 conj-* 方法完全相同,只是一个是 deftype,另一个是普通 defn,但第一个会出错,而第二个会成功。这是为什么?

最佳答案

这是因为协议(protocol)不支持可变数量的参数。

你能做的是:

(conj1-*  [dk & es] "Adding multiple elements to the deck"))

进入

(conj1-*  [dk es] "Adding multiple elements to the deck"))

这样 es 参数将是向量并调用如下:

(conj1-* a [1 2])

关于clojure - 在 deftype 中使用原子时出现奇怪的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12169508/

相关文章:

clojure - pmap 和线程数

if-statement - Clojure:if 中的多个任务

在 lein deps 期间,使用 OpenJDK 9 在 Travis CI 上构建 Clojure 失败

unit-testing - 如何为私有(private) clojure 函数编写单元测试?

math - 为什么 Clojure 返回 1N 而不是 1?

clojure - 绕过 Compojure 中的链的自定义中间件

java - 如何将 String[] 参数传递给 Java 函数?

clojure - ring:将 http 请求的正文读取为字符串

java - 从 clojure 项目创建可执行 jar 文件?

json - Clojure 使用 ring-json 编码 Joda DateTime