通过关键字查找惯用语的clojure地图

时间:2011-08-12 01:36:59

标签: clojure

假设我有一个使用关键字作为密钥的clojure地图:

(def my-car {:color "candy-apple red" :horsepower 450})

我知道我可以通过使用关键字或地图作为函数而另一个作为参数来查找与关键字关联的值:

(my-car :color)
; => "candy-apple red"
(:color my-car)
; => "candy-apple red"

我意识到这两种形式在某些情况下都可以派上用场,但其中一种形式被认为是如上所示的直接使用的惯用语?

4 个答案:

答案 0 :(得分:39)

(:color my-car)是相当标准的。这有几个原因,我不会涉及所有这些原因。但这是一个例子。

由于:color是一个常量,而my-car不是常量,因此热点可以完全内联color.invoke(m)的动态调度,而m.invoke(color)则不能这样做(在一些java伪代码)。

如果my-car恰好是带有color字段而不是普通地图的记录,那就更好了:clojure编译器可以发出代码来检查“嘿,如果my-car是CarType的一个实例,然后只返回my-car.color;否则执行所有复杂,缓慢的hashmap查找。“

答案 1 :(得分:24)

来自library coding standards

  
      
  • 使用关键字优先语法访问对象的属性:

    (:property object-like-map)
    
  •   
  • 使用collection-first语法从集合中提取值(如果集合可能为nil,则使用get)。

    (collection-like-map key)
    (get collection-like-map key)
    
  •   

答案 2 :(得分:8)

我列出了支持和反对这两种形式的论据清单。 (编辑:添加了第三个选项 - (get map :key)这是我最喜欢的,尽管它有点冗长)

(:键映射)

的参数

1)请求编码标准

http://dev.clojure.org/display/community/Library+Coding+Standards

2)当map为nil

时仍然有效
> (:a nil)
  nil
> (nil :a)
  ERROR: can't call nil

---反驳---如果关键可能是零,其他形式更好

> ({:a "b"} nil)
  nil
> (nil {:a "b"})
  ERROR: can't call nil

3)更好地在对象集合上进行线程化和映射

(-> my-map
  :alpha
  fn-on-alpha
  :beta
  fn-on-beta
  :gamma

> (def map-collection '({:key "values"} {:key "in"} {:key "collection"}))
> (map :key map-collection)
  ("values" "in" "collection")

---反驳---线程的代码结构不同于 通常可以将不同的惯用倾向应用于地图访问 需要时

4)潜在的优化效益? (需要验证)

(map:key)

的参数

1)当key为非关键字或nil

时,不会抛出错误
> ({:a "b"} nil)
  nil
> (nil {:a "b"})
  ERROR: can't call nil
> ({"a" "b"} "a")
  "b"
> ("a" {"a" "b"})
  ERROR: string cannot be cast to IFn

2)与Clojure中列表访问的一致性

> ([:a :b :c] 1)
  :b
> (1 [:a :b :c])
  ERROR: long cannot be cast to IFn

3)与其他形式的对象访问相似

java>         my_obj  .alpha  .beta  .gamma  .delta
clj >     ((((my-map  :alpha) :beta) :gamma) :delta)
clj > (get-in my-map [:alpha  :beta  :gamma  :delta])
cljs> (aget   js-obj  "alpha" "beta" "gamma" "delta")

4)从同一个地图(单独的行)访问多个键时的对齐

> (my-func
    (my-map :un)
    (my-map :deux)
    (my-map :trois)
    (my-map :quatre)
    (my-map :cinq))
> (my-func
    (:un my-map)
    (:deux my-map)
    (:trois my-map)
    (:quatre my-map)
    (:cinq my-map))

---反驳---从多个地图访问相同的密钥时对齐更糟糕

> (my-func
    (:key map-un)
    (:key map-deux)
    (:key map-trois)
    (:key map-quatre)
    (:key map-cinq)
> (my-func
    (map-un :key)
    (map-deux :key)
    (map-trois :key)
    (map-quatre :key)
    (map-cinq :key)

(get map:key)

的参数

1)如果arg1是map / vector / nil并且arg2是key / index / nil

,则不会导致错误
> (get nil :a)
  nil
> (get nil nil)
  nil
> (get {:a "b"} nil)
  nil
> (get {:a "b"} :q)
  nil
> (get [:a :b :c] nil)
  nil
> (get [:a :b :c] 5)
  nil

2)形式与其他Clojure功能的一致性

> (get {:a "b"} :a)
  :b
> (contains? {:a "b"} :a)
  true
> (nth [:a :b :c] 1)
  :b
> (conj [:a :b] :c)
  [:a :b :c]

3)地图优先的对齐优势

> (my-func
    (get my-map :un)
    (get my-map :deux)
    (get my-map :trois)
    (get my-map :quatre)
    (get my-map :cinq))

4)Get-in可以通过一次调用用于嵌套访问

> (get-in my-map [:alpha  :beta  :gamma  :delta])
> (aget   js-obj  "alpha" "beta" "gamma" "delta")

来源:在http://tryclj.com/上进行测试

答案 3 :(得分:0)

我想说要么是惯用的。唯一需要注意的是,第二种形式仅适用于关键字。我认为这是一个刻意的设计选择,它会让它更有理由成为惯用语。