2014-06-17 20 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传递,因此无法可靠区分步行中的矢量条目。我认为你将需要使用你自己的步行实施。