【问题标题】:Why does using keywords or symbols as functions to lookup values from maps work?为什么使用关键字或符号作为函数从地图中查找值有效?
【发布时间】:2011-08-02 16:43:46
【问题描述】:

引自Clojure 之乐,第 4.3.1 节--

因为关键字是自我评估的并提供快速的相等性检查,所以它们几乎总是在映射键的上下文中使用。使用关键字作为映射键的一个同样重要的原因是它们可以用作函数,将映射作为参数来执行值查找:

(def population {:zombies 2700, :humans 9})
(:zombies population)
;=> 2700
(println (/ (:zombies population)
(:humans population))
"zombies per capita")
; 300 zombies per capita

我不清楚这里发生了什么。不知何故,(:zombies population) 必须转换为 (get population :zombies),对吧?这究竟是如何工作的?关键字对自身求值,而不是对函数求值。读者是否会注意列表中的第一件事是关键字的情况,然后添加 get 并将关键字移动到列表末尾?

【问题讨论】:

    标签: clojure


    【解决方案1】:

    来自official documentation的引用:

    关键字使用可选的第二个参数(默认值)为一个参数(映射)的 invoke() 实现 IFn。例如 (:mykey my-hash-map :none) 的含义与 (get my-hash-map :mykey :none) 相同。请参阅获取。

    而且 Clojure 可以将关键字作为函数调用,因为它实现了与函数相同的接口。符号也是如此……

    【讨论】:

    • 有趣的是,第一个参数不一定是地图: (:foo :bar :baz) 产生 :baz
    • @KingCode 如果不是ILookup、java MapIPersistentSet,则RT 中的getFrom 只返回null,在这种情况下@ Keyword 中的 987654328@ 方法只返回 notFound 值,或者在您的示例中返回 :baz
    【解决方案2】:

    关键字功能,在各个方面。没有读者魔法,如果你尝试(let [m {:humans 100}, k :humans] (k m)),你会看到。我希望你会同意读者不可能把它变成一个 get (编译器可以,但你可以假装我已经使 k 的值依赖于编译器无法预测的 if 表达式,例如用户输入)。

    因为 Clojure 的核心数据类型是接口,而 Java 对象可以实现很多接口,所以一条数据可以有多种类型。是关键字吗?是的。它是一个函数吗?也可以:

    user> (keyword? :k)
    true
    user> (ifn? :k)
    true
    user> (.invoke :k {:k 1})
    1
    

    【讨论】:

      【解决方案3】:

      关键字实现 IFn,

      https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Keyword.java

      它的invoke方法处理调用get。

      【讨论】:

        猜你喜欢
        • 2021-04-02
        • 2012-07-24
        • 2015-10-23
        • 2012-05-01
        • 2015-01-31
        • 2012-01-01
        • 2015-04-13
        • 1970-01-01
        • 2010-12-04
        相关资源
        最近更新 更多