Clojure 解构映射参数:键与老式let
从Scheme的背景中学习Clojure,我的直觉是编写如下代码:Clojure 解构映射参数:键与老式let,clojure,Clojure,从Scheme的背景中学习Clojure,我的直觉是编写如下代码: (defn my-func [data] (let [right (:right data) left (:left data)] ... body ... )) 然而,我很快就被告知模式匹配是Clojure(或者说Haskell和Scala)的一个重要特性,因此我觉得不得不写: (defn my-func [ {:keys [right left] } ] ... body ...)
(defn my-func [data]
(let [right (:right data)
left (:left data)]
... body ... ))
然而,我很快就被告知模式匹配是Clojure(或者说Haskell和Scala)的一个重要特性,因此我觉得不得不写:
(defn my-func [ {:keys [right left] } ]
... body ...)
所以我的代码现在充斥着这种语法。不知怎么的,我不喜欢它。我发现我的代码不太吸引人,可读性可能更低(但这可能是因为缺乏习惯性Clojure的经验,所以随着时间的推移,它会变得更好)
所以我想问,是否有一个基本的理由使用一种风格而不是另一种?例如,编译器生成的字节码在第二种情况下效率要高得多。或者我还应该知道其他原因吗?键的解构只是一种语法糖,实际上扩展为一系列调用
get
和符号赋值。例如:
(macroexpand-1
'(let [{:keys [a b]} {:a 1 :b 2}]))
扩展为:
(let*
[map__2507
{:a 1, :b 2}
map__2507
(if (clojure.core/seq? map__2507) (clojure.lang.PersistentHashMap/create (clojure.core/seq map__2507)) map__2507)
a
(clojure.core/get map__2507 :a)
b
(clojure.core/get map__2507 :b)])
解构的主要目标(请注意,它只是解构,而不是完全模式匹配)是简洁的代码,不涉及性能优化
要说明没有:keys
解构的代码是如何更加详细,请看一个示例:
(let [{:keys [id name address age salary]} person]
...)
vs
:keys
解构只是一种语法糖,实际上扩展为对get
的一系列调用和对符号的赋值。例如:
(macroexpand-1
'(let [{:keys [a b]} {:a 1 :b 2}]))
扩展为:
(let*
[map__2507
{:a 1, :b 2}
map__2507
(if (clojure.core/seq? map__2507) (clojure.lang.PersistentHashMap/create (clojure.core/seq map__2507)) map__2507)
a
(clojure.core/get map__2507 :a)
b
(clojure.core/get map__2507 :b)])
解构的主要目标(请注意,它只是解构,而不是完全模式匹配)是简洁的代码,不涉及性能优化
要说明没有:keys
解构的代码是如何更加详细,请看一个示例:
(let [{:keys [id name address age salary]} person]
...)
vs
当你写这篇文章时:
(defn my-func [{:keys [right left]}]
,,,)
与此相同:
(defn my-func [data]
(let [{:keys [right left]} data]
,,,))
(defn my-func [data]
(let [right (:right data)
left (:left data)]
,,,))
与此相同:
(defn my-func [data]
(let [{:keys [right left]} data]
,,,))
(defn my-func [data]
(let [right (:right data)
left (:left data)]
,,,))
,使用更简洁的形式没有性能优势。然而,还有一个好处:即简洁
,解构键的主要优点是,每个键名只需写一次,而不是两次
,直接在函数的参数向量中进行解构会降低代码的可读性,这就是为什么它在Clojure中并不常见的原因
最棒的是,由于Clojure中的参数命名并没有完成解构,因此您可以在这两个方面都做到最好(我上面给出的第二种形式):
这样,您既可以获得可读性(尤其是如果您将参数命名为比数据更好的名称),又可以获得简洁性(通过使用:键解构)。编写此文件时:
(defn my-func [{:keys [right left]}]
,,,)
与此相同:
(defn my-func [data]
(let [{:keys [right left]} data]
,,,))
(defn my-func [data]
(let [right (:right data)
left (:left data)]
,,,))
与此相同:
(defn my-func [data]
(let [{:keys [right left]} data]
,,,))
(defn my-func [data]
(let [right (:right data)
left (:left data)]
,,,))
,使用更简洁的形式没有性能优势。然而,还有一个好处:即简洁
,解构键的主要优点是,每个键名只需写一次,而不是两次
,直接在函数的参数向量中进行解构会降低代码的可读性,这就是为什么它在Clojure中并不常见的原因
最棒的是,由于Clojure中的参数命名并没有完成解构,因此您可以在这两个方面都做到最好(我上面给出的第二种形式):
通过这种方式,您既可以获得可读性(尤其是如果您将参数命名为优于数据的名称),也可以获得简洁性(通过使用:keys
解构)。为了完整性,这来自Clojure:
惯用代码经常使用解构。但是,如果要将子结构作为调用方协定的一部分进行通信,则只应在arg列表中进行分解。否则,在第一线let中进行解构。示例:从书中可以看出,该测试失败,在arg列表中进行了太多的解构
为了完整起见,这来自Clojure:
惯用代码经常使用解构。但是,如果要将子结构作为调用方协定的一部分进行通信,则只应在arg列表中进行分解。否则,在第一线let中进行解构。示例:从书中可以看出,该测试失败,在arg列表中进行了太多的解构
正如Piotrek所提到的,最大的好处是您不需要重复每个名称两次(例如,符号“right”和关键字“:right”),并且符号“data”从每行以及arg列表中删除。感谢Piotrek/AlanAs Piotrek所提到的这么多,最大的好处是您不需要重复每个名称两次(例如,符号“right”)和关键字“:right”),并且符号“data”从每行以及arg列表中删除。非常感谢Piotrek/Alan非常感谢Sam!也谢谢你提供的关于分解v模式匹配的参考资料非常感谢Sam!也谢谢你提供的关于v模式匹配的参考资料非常感谢你,瓦伦丁!非常感谢你,瓦伦丁!