【问题标题】:What is meant by destructuring in Clojure?Clojure 中的解构是什么意思?
【发布时间】:2014-08-20 01:39:00
【问题描述】:

我是一名 Java 并且正在学习 clojure。

clojure 中的解构究竟是什么?

我可以看到this博客说:

最简单的解构示例是为 向量。

user=> (def point [5 7])
#'user/point

user=> (let [[x y] point]
         (println "x:" x "y:" y))
x: 5 y: 7

他所说的assigning the values of a vector 是什么意思?它的真正用途是什么?

提前致谢

【问题讨论】:

    标签: clojure


    【解决方案1】:

    point 是一个包含值向量的变量。 [x y] 是变量名的向量。

    当您将point 分配给[x y] 时,解构 意味着每个变量都被分配了值中的相应元素。

    这只是一种更简单的写法:

    (let [x (nth point 0) y (nth point 1)]
        (println "x:" x "y:" y))
    

    请参阅 Clojure let binding forms 了解使用解构的另一种方式。

    【讨论】:

    • 我是Java背景,是不是像在旧变量的基础上创建新变量一样?
    • 我不太了解Java,但我认为它没有这样的东西。它不是创建新变量,它只是用于同时从另一个变量的不同部分绑定多个变量的语法糖。
    • @sriram 就像创建新的 本地 基于旧的变量 ,但是,就像 Java finals 一样,它们不是可变的。任何带有参数的letfn 都可以做到这一点——不仅仅是那些带有解构的。
    【解决方案2】:

    就是用符号来描绘一些数据的结构

    ((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]
    

    将这些 ^ 示例粘贴到 REPL 中,然后试一试看看它是如何工作的。

    【讨论】:

    • 我喜欢第一句话:生动简洁。讨厌!为什么我不这么说。
    【解决方案3】:

    “解构”一词听起来比实际更重。

    这就像在视觉上匹配形状和形状。例如:

    (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
      )
    

    这说明了基本思想。有很多细节(如果和但是,注意事项和注意事项),值得进一步深入阅读。这里有一些资源可以通过示例进行更多解释:

    我个人最喜欢的:Jay Fields 关于 Clojure 解构的帖子: http://blog.jayfields.com/2010/07/clojure-destructuring.html

    来自 Braveclojure 的解构简介: http://www.braveclojure.com/do-things/#3_3_3__Destructuring

    【讨论】:

      【解决方案4】:

      它用于命名数据​​结构的组件,并获取它们的值。

      假设你想要一个“人”结构。在 java 中,你会一路创建一个类,其中包含各种字段的构造函数、getter 和 setter,例如姓名、年龄、身高等。

      在 Clojure 中,您可以跳过“仪式”并简单地拥有一个带有 3 个插槽的向量,第一个是姓名,然后是年龄,最后一个是身高。现在您可以简单地命名这些“组件”并获取它们的值,如下所示:

      (def person ["Fred" 30 180])
      (let [[name age height] person]
        (println name age height))    ;; will print: Fred 30 180
      

      p.s - 有更好的方法可以在 clojure 中创建一个“人”(例如记录等),这只是了解解构作用的一个示例。

      【讨论】:

        【解决方案5】:

        解构是一种方便的功能,它允许通过分解复杂的数据结构(seq-ables 像向量或 associatives 来轻松创建本地绑定(不是变量!)像哈希映射),正如它所描述的here

        举个例子:

        (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 绑定和函数参数(fndefnletfn 等),也可用于返回包含此类解构模式的let 绑定的宏。

        需要注意的一个重要用法是使用 if-letwhen-let 宏。 if 语句始终在整个表单上进行评估,即使解构绑定本身评估为 nil

        (if-let [{:keys [a b]}
                {:c 1 :d 2}]
          (println a b)
          (println "Not this one"))
        

        【讨论】:

          【解决方案6】:

          解构通过将每个名称绑定到对象的相应部分来将名称模式绑定到复杂对象。

          要绑定到一个序列,你需要提供一个名称的向量。比如……

          (let [[x y] (list 5 7)] ... )
          

          ... 等价于

          (let [x 5, y 7] ... )
          

          要绑定到 map通过索引查找的向量,您需要提供 name-to-key 的 map 对。比如……

          (let [{x 0, y 1} [5 7]] ... )
          

          ... 等同于上述两者。

          正如其他人所提到的,你可以找到这个强大机制的完整描述here

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多