online - Búsqueda idiomática del mapa de clojure por palabra clave
clojure web framework (4)
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 usando la palabra clave o el mapa como una función y la otra como su 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 una de ellas más idiomática para un uso sencillo, como se muestra arriba?
Desde los estándares de codificación de la biblioteca :
Use la primera sintaxis de palabras clave para acceder a las propiedades de los objetos:
(:property object-like-map)
Use la sintaxis de la colección primero para extraer valores de una colección (o use obtener 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: Se agregó la tercera opción - (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 codificación.
http://dev.clojure.org/display/community/Library+Coding+Standards
2) Todavía 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 sobre 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 de código de los hilos es diferente a la habitual, por lo que se pueden aplicar diferentes tendencias idiomáticas para el acceso al mapa cuando sea necesario
4) ¿Beneficio potencial de optimización? (necesita verificación)
Argumentos para (mapa: clave)
1) No arroja error cuando la clave no es una 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 acceso de 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 varias teclas desde el 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 --- peor alineación 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 la 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 del 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) La entrada puede utilizarse para el acceso anidado con una sola llamada
> (get-in my-map [:alpha :beta :gamma :delta])
> (aget js-obj "alpha" "beta" "gamma" "delta")
Fuente: pruebas 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 de diseño deliberada, le daría más razones para ser idiomático.
(:color my-car)
es bastante estándar. Hay algunas razones para esto, y no voy a entrar en todos ellos. Pero he aquí un ejemplo.
Porque :color
es una constante, y my-car
no lo es, hotspot puede color.invoke(m)
completamente el envío dinámico de color.invoke(m)
, que no puede hacer con m.invoke(color)
(en algún pseudo-código de Java) .
Eso se pone aún mejor si my-car
a veces es un registro con un campo de color
lugar de un mapa plano: el compilador de clojure puede emitir código para verificar "hey, si my-car
es una instancia de CarType, simplemente devuelva my-car.color
; de lo contrario, realice todas las búsquedas de hashmap complicadas y lentas ".