6

跟进这个问题:Idiomatic clojure map lookup by keyword

可以通过多种方式使用 clojure 进行地图访问。

(def m {:a 1}

(get m :a) ;; => 1
(:a m) ;; => 1
(m :a) ;; => 1

我知道我主要使用第二种形式,有时使用第三种,很少使用第一种。使用每个的优点(速度/可组合性)是什么?

4

6 回答 6

12

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
于 2013-01-23T23:02:05.423 回答
3

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

对于使用键和未找到值调用的映射也是如此。那么,有什么优势呢?由于这两种方式归结为几乎相同,性能方面我不会说什么。这只是语法上的方便。

于 2013-01-23T21:53:51.120 回答
2

您可以传递getpartialetc. 来构建 HOF 以弄乱您的数据,尽管它不会经常出现。

user=> (def data {"a" 1 :b 2})
#'user/data
user=> (map (partial get data) (keys data))
(1 2)

当数据以字符串为键时,我经常使用第三种形式

于 2013-01-23T21:45:23.653 回答
1

我认为没有速度差异,即使是这种情况,这也将是一个实现细节。

就我个人而言,我更喜欢第二种选择 (:am),因为它有时会使代码看起来更容易一些。例如,我经常需要遍历一系列映射:

(def foo '({:a 1} {:a 2} {:a 3}))

如果我想过滤 :a 的所有值,我现在可以使用:

(map :a foo)

代替

(map #(get % :a) foo)

或者

(map #(% :a) foo)

当然,这是个人口味的问题。

于 2013-01-23T20:58:50.940 回答
0

要添加到列表中,get 在使用 threading 宏时也很有用->,您需要通过不是关键字的键来访问

(let [m {"a" :a}] (-> m (get "a")))

于 2013-01-24T14:23:29.710 回答
0

使用关键字优先方法的一个优点是它是在映射为 nil 的情况下以宽容的行为访问值的最简洁方法。

于 2013-01-25T08:53:07.997 回答