2013-01-23 28 views
6

从这个问题的后续行动:使用Clojure的Idiomatic clojure map lookup by keyword什么优势有没有使用“得到”,而不是访问一个地图

地图的访问可以通过多种方式来完成。

(def m {:a 1} 

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

我知道我主要使用第二种形式,有时第三种,很少是第一种。各自使用的优点(速度/组合性)有哪些?

+1

查看您链接问题中的答案。想到的唯一另外一件事就是获得3-arity版本(get map key not found),你在哪里得到(双关语)来指定默认值。 –

+2

@ A.Webb你可以为所有三种用途指定一个默认值:'(:k m默认值)'和'(m:k默认值)'都可以,只要m不是零。 – amalloy

+0

@amalloy啊,很酷,谢谢你指出了! –

回答

3

the clojure web page我们看到

地图实现IFN一个说法,为的invoke()(一键很多)与 可选的第二个参数(默认值),即地图是其功能 其键。零键和值都可以。

有时在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

对于使用键和未找到值调用的映射也是如此。那么,有什么优势?既然两种方式都差不多,性能方面我什么都不会说。这只是语法上的便利。

1

我不认为存在速度差异,即使情况如此,这将是一个实施细节。

就我个人而言,我更喜欢第二个选项(:a m),因为它有时会让代码变得更容易。例如,我经常通过地图的序列迭代:

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

如果我要筛选的所有值:一个我现在可以使用:

(map :a foo) 

而不是

(map #(get % :a) foo) 

(map #(% :a) foo) 

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

2

您可以通过getpartial等建立HOFs与您的数据搞乱,虽然它不经常出现。

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

我用第三种形式当数据字符串作为键

+2

这并没有真正解决这个问题。你可以像'(地图数据(键数据))'一样容易地获得'(vals data)'的等价物。 – amalloy

+0

问题的关键在于get可以在函数转换函数中组合,以在数据映射可用之前生成数据转换函数。这个例子说明了这一点,尽管实际上它与其他特定于问题的约束结合在一起。 –

12

get是有用的,当在地图可能是零或不一个地图,关键可能是一些不可赎回(即不是关键字)

(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 
0

要添加到列表中,得到的是也有用使用线程宏观->,你需要通过一个按键是不是关键字

(let [m {"a" :a}] (-> m (get "a"))) 使用关键字第一种方法是在访问与价值的最简洁的方式

0

一个优点访问时在地图为零的情况下的宽容行为。

相关问题