Búsqueda en el mapa de Idiomatic clojure por palabra clave

Digamos que tengo un mapa de clojure que usa palabras clave como sus claves:

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

Sé que puedo buscar el valor asociado con la palabra clave ya sea usando la palabra clave o el mapa como una función y el otro como argumento:

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

Me doy cuenta de que ambas formas pueden ser útiles para ciertas situaciones, pero ¿se considera que una de ellas es más idiomática para el uso directo como se muestra arriba?

(:color my-car) es bastante estándar. Hay algunas razones para esto, y no entraré en todas. Pero aquí hay un ejemplo.

Porque :color es una constante y my-car no lo es, el punto de acceso puede color.invoke(m) completo el envío dynamic de color.invoke(m) , lo que no puede hacer con m.invoke(color) (en algún pseudo-código java) .

Eso es incluso mejor si my-car es a veces un registro con un campo de color lugar de un mapa simple: el comstackdor de clojure puede emitir código para verificar “hey, si my-car es una instancia de CarType, entonces simplemente devuelva my-car.color ; de lo contrario, realiza toda la búsqueda complicada, lenta y hashmap “.

De los estándares de encoding de la biblioteca :

  • Utilice la syntax de palabra clave para acceder a las propiedades en los objetos:

     (:property object-like-map) 
  • Utilice la syntax de colección primera para extraer valores de una colección (o use get si la colección puede ser nula).

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

Junté una lista de argumentos a favor y en contra de las dos formas. ( Editar: tercera opción añadida – (get map :key) que es mi nuevo favorito a pesar de ser un poco más detallado)

Argumentos para (: mapa clave)

1) Solicitado en estándares de encoding

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

2) Aún funciona cuando el mapa es nulo

 > (:a nil) nil > (nil :a) ERROR: can't call nil 

— contraargumento — si la clave puede ser nula, otras formas son mejores

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

3) Funciona mejor para enhebrar y mapear colecciones de objetos

 (-> 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") 

— contraargumento — la estructura del código de subprocesamiento es diferente de lo habitual, por lo que se podrían aplicar diferentes tendencias idiomáticas para acceder al mapa cuando sea necesario

4) ¿Beneficio de optimización potencial? (necesita verificación)

Argumentos para (mapa: clave)

1) No arroja un error cuando la clave no es palabra clave o nula

 > ({: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) Consistencia con el acceso a la lista en Clojure

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

3) Similitud con otras formas de acceso a objetos

 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) Alineación al acceder a múltiples claves del mismo mapa (líneas separadas)

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

— contraargumento — alineamiento peor al acceder a la misma clave desde múltiples mapas

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

Argumentos para (obtener mapa: clave)

1) NUNCA causa un error si arg1 es map / vector / nil y arg2 es 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) Consistencia en forma con otras funciones de 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) Beneficios de alineación de mapa primero

 > (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 se puede utilizar para el acceso nested con una sola llamada

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

Fuente: prueba en http://tryclj.com/

Yo diría que cualquiera es idiomático. La única advertencia es que la segunda forma solo funciona con palabras clave. Lo cual, supongo que al ser una elección deliberada de diseño, le daría más razones para ser idiomático.