->我仍然不完全理解两个 Clojure 箭头宏 thread-first和 thread-last 宏之间的区别->>。在阅读https://clojure.org/guides/threading_macros时,我了解到线程优先 ->是单个对象上嵌套操作的替代表达式,每个数据步骤都使用该对象作为输入参数,执行独立的操作。
(defn transformation [object]
(transform2 (transform1 object)))
Run Code Online (Sandbox Code Playgroud)
变成
(defn transformation [object]
(-> object
(transform1) ;; object as implicit argument
(transform2))) ;; object as implicit argument
Run Code Online (Sandbox Code Playgroud)
当使用威胁最后->>运算符时,每个转换都使用前面转换的输出作为隐式参数:
(defn transformation [object]
(->> object
(transform1) ;; object as implicit argument
(transform2))) ;; (transform1 object) as implicit argument
Run Code Online (Sandbox Code Playgroud)
这些差异有什么实际意义?我知道使用威胁优先->对地图和字典进行操作是有意义的,其中每个转换都会创建原始实例的新副本,必须为下一个操作提供该副本。然而,在许多情况下,两个运算符实际上表现相同:
(->> [2 5 4 1 3 6] (reverse) (rest) (sort) (count)) ;; => 5
(-> [2 5 4 1 3 6] (reverse) (rest) (sort) (count)) ;; => 5
Run Code Online (Sandbox Code Playgroud)
实际的区别在于宏将变量(以及后续结果)“插入”到表达式中的位置:
(ns so.example)
(defn example-1 [s]
(-> s
(str "foo")))
(defn example-2 [s]
(->> s
(str "foo")))
(example-1 "bar")
;=> "barfoo"
(example-2 "bar")
;=> "foobar"
Run Code Online (Sandbox Code Playgroud)
所以(-> "bar" (str "foo"))与 相同 且(str "bar" "foo")与(->> "bar" (str "foo"))相同(str "foo" "bar")。使用一元函数->做->>同样的事情。
当您需要更灵活地确定应在何处插入这些结果时,您可以使用as->:
(ns so.example)
(defn example-3 [s]
(as-> s v
(str "foo" v "foo")))
(example-3 "bar")
;=> "foobarfoo"
Run Code Online (Sandbox Code Playgroud)