【问题标题】:clojure let destructure java collectionclojure 让我们解构 java 集合
【发布时间】:2016-09-04 16:49:09
【问题描述】:

我是 Clojure 的新手,对 let 解构感到困惑:

java.util.ArrayList

(def arr (java.util.ArrayList. [1 2 3 4]))
;; => #'ns/arr

在解构时:

(let [[a b] arr]
   (+ a b))
;; => 3

一切正常,但是:

(let [{a 0 b 1} arr]
   (+ a b))
;; caught NullPointerException

我忽略了哪些点?

【问题讨论】:

    标签: java clojure


    【解决方案1】:

    您可以通过将let 扩展为let* 来查看此行为的原因:

    (macroexpand-1
     '(let [[a b] arr]
        (+ a b)))
    ;;=> (let* [vec__1 arr
    ;;          a (clojure.core/nth vec__1 0 nil)
    ;;          b (clojure.core/nth vec__1 1 nil)]
    ;;     (+ a b))
    
    (macroexpand-1
     '(let [{a 0 b 1} arr]
        (+ a b)))
    ;;=> (let* [map__1 arr
    ;;          map__1 (if (clojure.core/seq? map__1)
    ;;                   (clojure.lang.PersistentHashMap/create
    ;;                    (clojure.core/seq map__1))
    ;;                   map__1)
    ;;          a (clojure.core/get map__1 0)
    ;;          b (clojure.core/get map__1 1)]
    ;;     (+ a b))
    

    如您所见,顺序解构使用nth 函数,而关联解构使用get 函数。而nth 使用clojure.lang.RT/nth 方法,它支持ArrayList 实现的RandomAccess 接口,get 使用clojure.lang.RT/get,它不支持RandomAccessget 的默认大小写返回 null,这就是你得到 NullPointerException 的原因。

    顺便说一句,因为LinkedList 没有实现RandomAccess,这也会报错:

    (def linked (java.util.LinkedList. [1 2 3 4]))
    
    (let [[a b] linked]
      (+ a b))
    ;; java.lang.UnsupportedOperationException: nth not supported on this type: LinkedList
    

    【讨论】:

    • 使用原生 Clojure 列表获得相同的结果:(def arr (list 1 2 3 4))
    猜你喜欢
    • 2011-05-17
    • 2012-03-05
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-23
    相关资源
    最近更新 更多