Clojure线程第一个宏(>;)与线程最后一个宏(>;)的实际区别是什么?
我仍然不完全理解两个Clojure arrow宏之间的区别,即先执行thread firstClojure线程第一个宏(>;)与线程最后一个宏(>;)的实际区别是什么?,clojure,Clojure,我仍然不完全理解两个Clojure arrow宏之间的区别,即先执行thread first->和后执行thread last宏->。 在通读过程中,我了解到thread first-是单个对象上嵌套操作的替代表达式,每个数据步骤使用对象作为输入参数,执行独立操作 (defn transformation [object] (transform2 (transform1 object))) 变成 (defn transformation [object] (-> object
->
和后执行thread last宏->
。
在通读过程中,我了解到thread first-
是单个对象上嵌套操作的替代表达式,每个数据步骤使用对象作为输入参数,执行独立操作
(defn transformation [object]
(transform2 (transform1 object)))
变成
(defn transformation [object]
(-> object
(transform1) ;; object as implicit argument
(transform2))) ;; object as implicit argument
使用threat last->
运算符时,每个转换都使用前面转换的输出作为隐式参数:
(defn transformation [object]
(->> object
(transform1) ;; object as implicit argument
(transform2))) ;; (transform1 object) as implicit argument
这些差异的实际含义是什么?我理解在地图和字典上的操作中使用threat-first->
是有意义的,每次转换都会创建原始实例的新副本,必须为下一次操作提供该副本。
但是,在许多情况下,两个操作符的行为实际上是相同的:
(->> [2 5 4 1 3 6] (reverse) (rest) (sort) (count)) ;; => 5
(-> [2 5 4 1 3 6] (reverse) (rest) (sort) (count)) ;; => 5
实际区别在于宏将变量(以及后续结果)“插入”到表达式中:
(ns so.示例)
(定义示例1[s]
(->s
(str“foo”))
(示例2[s]
(->s
(str“foo”))
(示例1“巴”)
;=> “巴福”
(示例2“条形图”)
;=> “foobar”
所以(>“bar”(str“foo”)
与(str“bar”“foo”)
相同,(>“bar”(str“foo”)
与(str“foo”“bar”)
相同。使用一元函数->
和->
也可以执行相同的操作
当您需要更灵活地插入这些结果时,可以使用as->
:
(ns so.示例)
(参见示例3[s]
(as->s v)
(str“foo”v“foo”))
(示例3“条形图”)
;=> “foobarfoo”
将作为->
作为一个答案跟进,纯粹是因为我无法在注释中格式化代码
以下是我们在工作中使用的代码库中的as->
:
(-> date
(.getTime)
(as-> millis
(/ (- (.getTime (java.util.Date.)) millis)
1000 60 60 24))
(long)
(min days))
可以展开该计算,并使用
->
将线程值放置在-
表达式的末尾,但可能更难读取。也可以将其展开,使->
单独就足够了(通过对线程值求反,然后将其添加到(.getTime(java.util.Date.))
),但我认为这会使它更难阅读。我认为您对->
的工作方式存在误解
你说
->
是单个对象上嵌套操作的替代表达式,每个数据步骤使用对象作为输入参数,执行独立操作->
->
运算符时,每个转换都使用前面转换的输出作为隐式参数->
和->
都正确。
这很容易测试,如下所示:
cljs.user=>(>[2 5 4 1 3 6]反向rest)
(3 1 4 5 2)
cljs.user=>(>[2 5 4 1 3 6]rest反向)
(6 3 1 4 5)
如果将sort
添加到调用链的末尾,就像在您的示例中一样,您不会注意到这一差异,因为两个结果都将被排序
就像cfrik
所说的,当你只向一个函数传递一个参数时,那么第一个参数和最后一个参数是相同的(因为只有一个),这就是为什么当你的调用链中的所有函数都只接受一个参数时很容易混淆的原因,在您的示例中,您使用了计数
、排序
、休息
和反向
在中的文档中,您可能遗漏了另一件事,即许多使用序列的函数,如过滤器
,映射
,和减少
,都将序列作为最后一个参数作为约定,这样就可以使用->
链接对它们的调用,如
(->>(范围10)
(过滤均匀?)
(地图#(上升3%))
(减少+)
变成
(减少+(映射#(+3%)(过滤偶数?(范围10)))
而->
更适合于assoc
和update
等函数,它们(如您所说)处理单个对象,并将对象作为其第一个参数(将该对象上的“转换/更新”作为其余参数),因此您可以执行以下操作
(->人
(助理:头发颜色:灰色)
(更新:时代公司)
变成
(更新(助理人员:头发颜色:灰色):年龄公司)
为了更好地理解宏的工作原理,请尝试使用macroexpand-1
,如下所示
user>(宏扩展-1'(->)(范围10)
(过滤均匀?)
(地图#(上升3%))
(减少+)
(减少+(映射(fn*[p1_uuu21582_35;](+3 p1_uu21582_35;))(过滤偶数(范围10)))
参数
macroexpand-1
应该是函数调用的引用版本,结果将是扩展的函数调用。好的,我的两个示例行为相同的问题是它们只是一个嵌套的一元表达式链:(count(sort(rest(rest[2 5 4 1 3 6]))?@gitsrush是的,我这么说。但请等待其他答案;那里有很多很好的法学家,我根本不与他们相比;)@GitCrush或换句话说:对于单参数函数,“线程优先”和“-last”的“first”和“last”参数是相同的参数位置。只需注意:as->用于->链内部,而不是独立的-这就是为什么它的值参数是第一个,名称参数是第二个:(->s(str“后缀”)(as->x(str“{”x“}”))@customcommander您的示例太小/太简单,无法真正说明as->存在的原因