跟进这个问题:Idiomatic clojure map lookup by keyword
可以通过多种方式使用 clojure 进行地图访问。
(def m {:a 1}
(get m :a) ;; => 1
(:a m) ;; => 1
(m :a) ;; => 1
我知道我主要使用第二种形式,有时使用第三种,很少使用第一种。使用每个的优点(速度/可组合性)是什么?
跟进这个问题:Idiomatic clojure map lookup by keyword
可以通过多种方式使用 clojure 进行地图访问。
(def m {:a 1}
(get m :a) ;; => 1
(:a m) ;; => 1
(m :a) ;; => 1
我知道我主要使用第二种形式,有时使用第三种,很少使用第一种。使用每个的优点(速度/可组合性)是什么?
get
当 map 可以是 nil 或 not-a-map 并且 key 可以是不可调用的东西(即不是关键字)时很有用
(def m nil)
(def k "some-key")
(m k) => NullPointerException
(k m) => ClassCastException java.lang.String cannot be cast to clojure.lang.IFn
(get m k) => nil
(get m :foo :default) => :default
从clojure网页我们看到
映射实现 IFn,用于一个参数(键)的调用()和可选的第二个参数(默认值),即映射是其键的函数。nil 键和值都可以。
有时,深入了解 Clojure 的内部结构会很有意义。如果您查看invoke
地图中的外观,您会看到:
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java#L196
它显然调用valAt
了地图的方法。
如果您查看get
使用地图调用该函数时的作用,这是对 的调用clojure.lang.RT.get
,这实际上归结为valAt
对地图的相同调用(地图实现 ILookUp 因为它们是Associatives):
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L634。
对于使用键和未找到值调用的映射也是如此。那么,有什么优势呢?由于这两种方式归结为几乎相同,性能方面我不会说什么。这只是语法上的方便。
您可以传递get
给partial
etc. 来构建 HOF 以弄乱您的数据,尽管它不会经常出现。
user=> (def data {"a" 1 :b 2})
#'user/data
user=> (map (partial get data) (keys data))
(1 2)
当数据以字符串为键时,我经常使用第三种形式
我认为没有速度差异,即使是这种情况,这也将是一个实现细节。
就我个人而言,我更喜欢第二种选择 (:am),因为它有时会使代码看起来更容易一些。例如,我经常需要遍历一系列映射:
(def foo '({:a 1} {:a 2} {:a 3}))
如果我想过滤 :a 的所有值,我现在可以使用:
(map :a foo)
代替
(map #(get % :a) foo)
或者
(map #(% :a) foo)
当然,这是个人口味的问题。
要添加到列表中,get 在使用 threading 宏时也很有用->
,您需要通过不是关键字的键来访问
(let [m {"a" :a}]
(-> m
(get "a")))
使用关键字优先方法的一个优点是它是在映射为 nil 的情况下以宽容的行为访问值的最简洁方法。