Clojure 映射中的函数调用顺序是否保证运行时顺序处理?

Does the order of function calls inside a Clojure map guarantee runtime order processing?

我正在处理以下功能:

(defn process-request [request]
  (if (not (db/empty?))
    {:person (db/get-person!) :violations (:violations (process-violations request))}
    {:person {} :violations ["no-person"]}))

我需要 process-violations 函数仅在数据库不为空时调用。这就是它位于 if 块中的原因。

但是,我还需要在 db/get-person! 函数之前调用它 。否则,该值将过时。

所以我想知道:

  • 我该怎么做?
  • 无论如何,映射中值的顺序是否足以保证一个函数总是在另一个函数之前被调用?

不,地图没有排序。对于小型文字地图,它可能会起作用,但你不应该依赖它,而对于更大的地图,它确实会失败:

user=> {0 (println 0) 1 (println 1) 2 (println 2) 3 (println 3) 4 (println 4) 5 (println 5) 6 (println 6) 7 (println 7) 8 (println 8) 9 (println 9)}
0
7
1
4
6
3
2
9
5
8
{0 nil, 7 nil, 1 nil, 4 nil, 6 nil, 3 nil, 2 nil, 9 nil, 5 nil, 8 nil}

但是使用 let 绑定总是很容易强制排序,这些绑定在 let 主体之前按顺序计算。

(let [person (db/get-person!)]
  {:person person :violations ...})

reader 会将代码中的地图读入地图,您不应对其进行任何顺序假设,因此不要依赖这些值的评估顺序。 (实际上,它是一个数组映射,它可能按照词法定义的相同顺序求值,但你不应该依赖它。)

(defn process-request [request]
  (if (not (db/empty?))
    (let [violations (:violations (process-violations request))
          person (db/get-person!)]
      {:person person :violations violations})
    {:person {} :violations ["no-person"]}))

会更安全。