引自 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并将关键字移动到列表的末尾?
答案 0 :(得分:24)
来自official documentation的引文:
关键字为一个参数(一个映射)的invoke()实现IFn,并带有可选的第二个参数(默认值)。例如(:mykey my-hash-map:none)表示与(get my-hash-map:mykey:none)相同。见get。
Clojure可以将关键字作为函数调用,因为它实现了与函数相同的接口。符号也一样......
答案 1 :(得分:18)
关键字是各种功能。没有读者魔法,因为你会看到你是否尝试(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
答案 2 :(得分:6)
关键字实施IFn,
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Keyword.java
并且其invoke方法处理调用get。