在练习 Clojure 时我注意到了这一点。偷看一个矢量按预期工作:
(let [v (vector 1 2 3)]
(peek v))
;; => 3
也偷看一个列表:
(let [l (list 1 2 3)]
(peek l))
;; => 1
但是,如果我首先对序列进行sort,它会恐慌!
(let [l (sort (list 1 2 3))]
(peek l))
;; => Unhandled java.lang.ClassCastException
class clojure.lang.ArraySeq cannot be cast to class
clojure.lang.IPersistentStack (clojure.lang.ArraySeq and
clojure.lang.IPersistentStack are in unnamed module of loader
'app')
为什么会这样? 谢谢!
peek
函数仅适用于 stack。在 Clojure 中,vector
或 list
都可以用作堆栈。对于任何其他序列类型,只需使用 first
获取初始元素。
如果你阅读了 Clojure 源代码,它使用了内置的 Java 排序算法:
(defn sort
"Returns a sorted sequence of the items in coll. If no comparator is
supplied, uses compare. comparator must implement
java.util.Comparator. Guaranteed to be stable: equal elements will
not be reordered. If coll is a Java array, it will be modified. To
avoid this, sort a copy of the array."
{:added "1.0"
:static true}
([coll]
(sort compare coll))
([^java.util.Comparator comp coll]
(if (seq coll)
(let [a (to-array coll)]
(. java.util.Arrays (sort a comp))
(with-meta (seq a) (meta coll)))
())))
函数
to-array
“映射到java.util.Collection.toArray()”。您可以在错误消息class clojure.lang.ArraySeq cannot be cast...
中看到这一点的提示。 peek
函数仅对 Clojure 类型进行操作,而 sort
返回不同的类型。
您可以检查 Clojure 类型具有的超类和接口,如下所示:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(verify
(is= clojure.lang.ArraySeq (type (sort [1 2 3])))
(is= (parents clojure.lang.ArraySeq)
#{clojure.lang.ASeq
clojure.lang.IReduce
clojure.lang.IndexedSeq})
(is= (ancestors clojure.lang.ArraySeq)
#{clojure.lang.ASeq
clojure.lang.Counted
clojure.lang.IHashEq
clojure.lang.IMeta
clojure.lang.IObj
clojure.lang.IPersistentCollection
clojure.lang.IReduce
clojure.lang.IReduceInit
clojure.lang.ISeq
clojure.lang.IndexedSeq
clojure.lang.Obj
clojure.lang.Seqable
clojure.lang.Sequential
java.io.Serializable
java.lang.Iterable
java.lang.Object
java.util.Collection
java.util.List})
)
使用这个模板项目.