【发布时间】:2016-07-27 05:00:15
【问题描述】:
我是 clojure 的新手,我正在尝试尽可能多地理解,但是文档太模糊了
当你有一个功能时
(fn [_ {:keys [kind]}] kind)
我的理解是该函数采用矢量图,但只想访问第二个参数{:keys..... 指定的键,对吗?
那我要传递多少个参数给这个函数呢? 1 还是 2?
它是一个向量吗? {:kind 1 :dog 2} 还是向量键值 (:kind {....})?
【问题讨论】:
我是 clojure 的新手,我正在尝试尽可能多地理解,但是文档太模糊了
当你有一个功能时
(fn [_ {:keys [kind]}] kind)
我的理解是该函数采用矢量图,但只想访问第二个参数{:keys..... 指定的键,对吗?
那我要传递多少个参数给这个函数呢? 1 还是 2?
它是一个向量吗? {:kind 1 :dog 2} 还是向量键值 (:kind {....})?
【问题讨论】:
您的函数需要两个参数(有 2 个参数)。第一个参数的名称是 _(下划线),通常表示未使用的变量。 (它是一个有效的变量名,它会被绑定,但按照约定不使用它,所以它表示一个占位符。)
第二个参数是解构的-{:keys [kind]},表示期望的值是一个map,解构后一个名为kind的变量会绑定到实际参数的key:kind的值(如果没有这样的键,则为零。)
所以你的函数需要两个参数,第一个被忽略,第二个必须是带有键 :kind 的映射(可能还有其他键,但它们被忽略了。)
((fn [_ {:keys [kind]}] kind) :foo {:kind :bar, :color :green})
=> :bar
附:我再次查看了您的问题,我意识到您的困惑可能来自哪里。语法[_ {:kind [kind]}] 看起来像一个在第二个位置包含地图的向量。这是正确的,但在 Clojure 中并非所有地方都使用向量表示法意味着您可以将向量粘贴到那里。 Clojure 用户为函数的形式参数列表使用方括号 - 这是 Clojure 中常见模式的一部分,即在可能需要序列的任何地方都使用向量文字。与其他需要在许多地方小心使用引号以避免将列表解释为函数应用程序表单的 Lisp 相比,它实际上非常方便。不过题外话,重点是fn(和defn)中的方括号表示参数列表,并不表示参数是向量。
【讨论】:
让我们给函数起个名字:
(defn splot [_ {:keys [kind]}] kind)
这是
的简写(defn splot [_ {kind :kind}] kind)
两个(位置)参数的函数:
_,通常未使用,并且:kind 条目绑定到本地kind;然后返回绑定到kind 的任何内容。
失败的绑定返回nil。
例如:
(splot "..." 6) ;nil
(splot "..." {}) ;nil
(splot "..." {:kind 77}) ;77
【讨论】:
(map (fn [_ x] [(rand-int 10) x]) (range) xs) 是一个有点奇怪的表达式,但显示了您可能会这样做的场景。
通过在 repl 中尝试给定的函数语法,可以很容易地了解它的作用。
+user=> ((fn [_ {:keys [kind]}] kind) (:kind {}))
ArityException Wrong number of args (1) passed to: user/eval1/fn--3 clojure.lang.AFn.throwArity (AFn.java:429)
+user=> ((fn [_ {:keys [kind]}] kind) nil (:kind {}))
nil
+user=> ((fn [_ {:keys [kind]}] kind) nil {:kind 1})
1
{:keys []} 解构语法是described pretty comprehensively in the official docs,它描述了绑定来自哈希映射的值的简写。在 Clojure 中,{} 是一个 hashmap,[] 是一个向量,它们是不可互换的。 (:foo m) 调用 get 在 m 中查找键 :foo 下的值。 (let [{:keys [foo]} {:foo "bar"}] ...) 和 (let [foo (:foo {:foo "bar"})] ...) 是等价的。
【讨论】:
(fn [{{[x y] :sam} :top :keys [z]} [{:strs [a]} {b 2}]] nil) - 请记住,您只能在 repl 中尝试,不要通过检查解构形式来分析它。