【问题标题】:Destructuring Maps in clojure -- unused keysclojure 中的解构映射——未使用的键
【发布时间】:2012-11-03 14:19:14
【问题描述】:

我已经定义了一个带有地图的函数。我想使用解构来访问这些值。但是,我还想检查是否有任何使用过的键。

所以,例如...

 (defun func1 [{:keys [a b c] :rest rest}]
    (println a b c)
    (println rest))

 (func1 {:a 1 :b 2 :c 3 :d 4})

会打印出来的

 1 2 3
 4

我想要这个的原因是,如果 rest 不为空,这可能是一个错误,我想发出信号。我知道 :as,我可以使用它。但是我需要将有效密钥列表存储两次。

我错过了什么吗?

菲尔

【问题讨论】:

    标签: clojure destructuring


    【解决方案1】:

    我真的不明白为什么你会想知道是否有一些你不关心的事情。如果您尝试执行“使用这些键执行特定操作,而使用其他键执行通用操作”之类的操作,您可以执行以下操作:

    (defn func [& {:keys [a b] :as args}]
      (println a b c)
      (println (dissoc args :a :b)))
    
    (func :a 3 :b :c 5) =>
      3 4
      {:c 5}
      nil
    

    如果您对必须两次提及关键字感到偏执,您可能也可以为此做点什么,但我无法想象这会值得。

    我想要这个的原因是,如果 rest 不为空,这可能是一个错误,我想发出信号。

    如果您担心传入的用户不是完全您想要的,那么地图可能不是适合使用的数据结构。

    【讨论】:

    • 我的逻辑是,如果他们传入了错误的键,那很可能是一个错误。我使用了地图,因为它似乎是一个足够明智的选择。不知道有什么更好的选择。该函数需要采用任意数量(包括无)的一组已定义参数。你会建议什么数据结构?
    • 当然,在这种情况下,地图仍然是最好的,我只是仍然不明白您为什么要限制自己(或者更确切地说:您的用户!)。不一定是它们传递了“错误”的键,而是它们具有更大的属性映射,这些属性不一定是为您的函数单独制作的。
    • 啊,是的,确实如此。我正在实施有效的 DSL。因此,在这种情况下,这些值很可能是用户直接编写的,而不是从其他地方生成的。所以他们不太可能有一个大的属性图。如果他们这样做了,那么他们总是可以使用选择键来解决我的限制。
    • 嗯,这是您的图书馆(或您为之工作的人的图书馆)。只要对你有用就可以。
    【解决方案2】:

    如果您关心对给定映射强制执行结构,Schema 可能是一个不错的选择(README 中的第一个示例):

    (ns schema-examples
      (:require [schema.core :as s
                 :include-macros true ;; cljs only
                 ]))
    
    (def Data
      "A schema for a nested data type"
      {:a {:b s/Str
           :c s/Int}
       :d [{:e s/Keyword
            :f [s/Num]}]})
    
    (s/validate
      Data
      {:a {:b "abc"
           :c 123}
       :d [{:e :bc
            :f [12.2 13 100]}
           {:e :bc
            :f [-1]}]})
    ;; Success!
    
    (s/validate
      Data
      {:a {:b 123
           :c "ABC"}})
    ;; Exception -- Value does not match schema:
    ;;  {:a {:b (not (instance? java.lang.String 123)),
    ;;       :c (not (integer? "ABC"))},
    ;;   :d missing-required-key}
    

    【讨论】:

      【解决方案3】:

      (Phil Lord,OP 毫无疑问已经转向其他问题,但对于任何有类似问题的人来说,这里有一个可能的解决方案。)

      您可以使用count 来测试地图的键数是否正确:

      (count {:a 1 :b 2 :c 3 :d 4}) ;=> 4
      

      这将返回 key/val 对的数量。只要你单独测试地图是否有必需的键,知道有太多的键会告诉你是否还有其他的。

      【讨论】:

      • 好主意,但它不能解决我的问题,因为您假设您必须传递所有密钥。我还需要能够仅传递其中一些密钥,但不能传递错误的密钥。最后,我走了一条不同的路,并没有通过解构来做到这一点,因为我需要对参数进行更丰富的处理。
      • 啊,我明白了。也许这会对其他人有所帮助。
      【解决方案4】:

      我喜欢plumbing 的做法:

      (use '[plumbing.core])
      (defnk f1 [a b c & rest]
          (prn [a b c])
          (prn rest))
      (f1 {:a 1 :b 2 :c 66 :z "fake"})
      
      [1 2 66]
      {:z "fake"}
      => nil
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-09
        • 1970-01-01
        • 2011-11-04
        • 1970-01-01
        • 1970-01-01
        • 2012-07-02
        相关资源
        最近更新 更多