我是一名Java程序员,正在学习Clojure。
Clojure中的解构是什么?
我看到这篇博客说:
解构的最简单示例是分配一个向量的值。
user=> (def point [5 7])
#'user/point
user=> (let [[x y] point]
(println "x:" x "y:" y))
x: 5 y: 7
他所说的“给向量分配值”是什么意思?它的真正用途是什么?谢谢。
point
是一个包含值向量的变量。[x y]
是变量名的向量。
当你将point
分配给[x y]
时,解构意味着每个变量都会被赋予相应值中的相应元素。
这只是一个更简单的写法:
(let [x (nth point 0) y (nth point 1)]
(println "x:" x "y:" y))
(def nums [1 2 3 4 5 6])
(let [[a b c & others] nums]
;; do something
)
Imagine the effect of the let binding as:
1 2 3 4 5 6
| | | ( )
v v v v
[a b c & others]
;; Now we can use a, b, c, others, and of course nums,
;; inside the let binding:
user=> (let [[a b c & others] nums]
(println a)
(println b)
(println c)
(println others)
(println nums))
1
2
3
(4 5 6)
[1 2 3 4 5 6]
目标是为了在let绑定或函数(即“词法作用域”内)的范围内,简洁地命名集合中的项。
为什么要“简洁”?如果没有解构,let绑定看起来会像这样:
(let [a (nth nums 0) ;; or (first nums)
b (nth nums 1) ;; or (second nums)
c (nth nums 2)
others (drop 3 nums)]
;; do something
)
((fn [[d [s [_ _]]]]
(apply str (concat (take 2 (name d)) (butlast (name s)) (drop 7 (name d))) ))
'(describing (structure (of data))))
=> "destructuring"
((fn [[d e _ _ _ _ _ i n g _ _ _ _ _ s t r u c t u r e & etc]]
[d e s t r u c t u r i n g]) "describing the structure of data")
=> [\d \e \s \t \r \u \c \t \u \r \i \n \g]
(let [[x y] (list 5 7)] ... )
...等同于
(let [x 5, y 7] ... )
(let [{x 0, y 1} [5 7]] ... )
...等价于上述两者。
正如其他人所提到的,您可以在此处找到有关这种强大机制的完整描述。
它用于命名数据结构的组件并获取它们的值。
比如你想要一个“人”结构。在Java中,你需要创建一个类,包括构造函数、各种字段的getter和setter,例如姓名、年龄、身高等。
在Clojure中,你可以跳过这些“仪式”,只需使用一个有3个插槽的向量,第一个是姓名,第二个是年龄,最后一个是身高。现在你可以简单地为这些“组件”命名并获取它们的值,就像这样:
(def person ["Fred" 30 180])
(let [[name age height] person]
(println name age height)) ;; will print: Fred 30 180
附言 - 在Clojure中有更好的方法来创建“person”(例如记录等),这只是一个例子,以便了解解构的作用。
解构是一种方便的特性,它允许通过拆分复杂的数据结构(如向量等可序列化对象或哈希映射等可关联对象)轻松创建本地绑定(不是变量!),如此处所述。
以以下示例为例:
(let [v [1 2 3 4 5 6]
v_0 (first v)
v_1 (nth v 1)
v_rest (drop 2 v)
m {:a 1 :b 2}
m_a (get m :a)
m_b (get m :b)
m_default (get m :c "DEFAULT")]
(println v, v_0, v_1, v_rest, m, m_a, m_b, m_default))
然后,可以使用解构绑定来简化上述代码,如下所示:
(let [[v_0 v_1 & v_rest :as v]
[1 2 3 4 5 6]
{m_a :a m_b :b m_default :c :or {m_default "DEFAULT"} :as m}
{:a 1 :b 2}]
(println v, v_0, v_1, v_rest, m, m_a, m_b, m_default))
解构模式可用于let
绑定和函数参数(fn
、defn
、letfn
等),还可在宏中使用,以返回包含这种解构模式的let
绑定。
需要注意的一个重要用法是在if-let
和when-let
宏中。即使解构绑定本身计算结果为nil
,if
语句也总是对整个形式进行评估:
(if-let [{:keys [a b]}
{:c 1 :d 2}]
(println a b)
(println "Not this one"))
final
一样,它们是不变的。任何带有参数的let
或fn
都可以实现这个功能——而不仅仅是具有解构的函数。 - Thumbnail