2014-06-17 22 views
1
(postwalk #(do (println "visiting:" %) 
       (if (vector? %) 
       (seq %) 
       %)) 
      [:title {:bu "hu"}]) 

我期待什麼名單(不printlns):(:title {:bu "hu"})變動矢量使用postwalk

我得到了什麼:

visiting: :title 
visiting: :bu 
visiting: hu 
visiting: [:bu hu] 
Stack trace of root exception is empty; this is likely due to a JVM optimization 
that can be disabled with -XX:-OmitStackTraceInFastThrow. 
java.lang.ClassCastException: 

爲什麼訪問[:bu hu]代替{:bu hu}?它似乎與嵌套的向量很好地工作,但扔了一張地圖,jvm生氣我和嘔吐無法理解的淫穢。

回答

4

我得到一個更好的堆棧跟蹤:

visiting: :title 
visiting: :bu 
visiting: hu 
visiting: [:bu hu] 

ClassCastException clojure.lang.Keyword cannot be cast to java.util.Map$Entry clojure.lang.ATransientMap.conj (ATransientMap.java:44) 

[:bu hu]不是地圖,它在地圖中的第一MapEntry。不幸的是,它實際上並不是clojure.lang.MapEntry的實例。 walk在您傳入postwalk的函數曾應用(postwalk內部調用walk)之前將它變成矢量。即使在reading the code之後,我仍然難以相信。

我不知道最好的解決方法是什麼。但我認爲至少知道它爲什麼會發生這種情況會對你有所幫助。

+0

很好的洞察力(+1)!我喜歡Clojure,但是這樣的問題讓我想起爲什麼我們爲編程語言發明了靜態類型系統。 – DaoWen

1

[:bu「hu」]是一個clojure.lang.MapEntry,並且postwalk將訪問地圖中的每個條目。可悲的是,clojure.walk/postwalk將MapEntry作爲clojure.lang.PeristentVector傳遞,因此無法可靠區分步行中的矢量條目。我認爲你將需要使用你自己的步行實施。