我会认为地图文字的评估顺序是一个实现细节,并且在地图文字中使用具有副作用的非常量表达式(例如设置原子状态)是自找麻烦。
对于定义明确的评估语义,请使用函数调用,其中保证从左到右评估参数。
(let [i (atom 0)]
(hash-map :a (swap! i inc) :b (swap! i inc) :c (swap! i inc)))
;=> {:a 1, :c 3, :b 2}
请注意,由于我们使用了哈希映射,因此键是乱序的,但值与写入顺序中的键相对应。
实施细节
地图字面量(1.5 版)的实现细节取决于几件事:
一个小例子会让这更清楚一点(也许):
user=> {:a 1, :b 2, :c 3}
{:a 1, :c 3, :b 2}
user=> (type *1)
clojure.lang.PersistentArrayMap
user=> (def m1 {:a 1, :b 2, :c 3})
#'user/m1
user=> m1
{:a 1, :c 3, :b 2}
user=> (type m1)
clojure.lang.PersistentHashMap
user=> (eval m1)
{:a 1, :c 3, :b 2}
user=> (type *1)
clojure.lang.PersistentArrayMap
但...
user=> (def m2 {:a ((fn [] 1)), :b 2, :c 3})
#'user/m2
user=> m2
{:a 1, :b 2, :c 3}
user=> (type m2)
clojure.lang.PersistentArrayMap