Pregunta

Tengo un java.util.HashMap objeto m (un valor de retorno de una llamada a código Java) y me gustaría conseguir un nuevo mapa con un adicional de par clave-valor.

Si m fueron un Clojure mapa, yo podría usar:

(assoc m "key" "value")

Pero tratando de que en un HashMap da:

java.lang.ClassCastException:java.util.HashMap no se puede convertir a clojure.lang.Asociativa

Suerte con seq ya sea:

(assoc (seq m) "key" "value")

java.lang.ClassCastException:clojure.lang.IteratorSeq no se puede convertir a clojure.lang.Asociativa

La única manera me las arreglé para hacerlo fue el uso de HashMap's propio put, pero que devuelve void así que tengo que devolver explícitamente m:

(do (. m put "key" "value") m)

Esto no es idiomático Clojure código, además de que soy la modificación de m en lugar de crear un nuevo mapa.

Cómo trabajar con un HashMap en una más Clojure-ish manera?

¿Fue útil?

Solución

Clojure hace que las colecciones de Java ss-poder, por lo que puede utilizar directamente las funciones de secuencia de Clojure en el java.util.HashMap .

Pero Assoc espera un clojure.lang.Associative lo que tendrá que convertir primero el java.util.HashMap a que:

(assoc (zipmap (.keySet m) (.values m)) "key" "value")

Editar: solución más simple:

(assoc (into {} m) "key" "value")

Otros consejos

Si va a interactuar con el código de Java, es posible que tenga que morder la bala y hacerlo de la manera de Java, utilizando .put. Esto no es necesariamente un pecado mortal; Clojure le da cosas como do y . específicamente para que pueda trabajar con código Java fácilmente.

assoc sólo funciona en las estructuras de datos de Clojure porque una gran cantidad de trabajo ha ido a por lo que es muy barato para crear nuevas copias (inmutables) de ellos con ligeras modificaciones. HashMaps Java no están destinados a trabajar de la misma manera. Habría que evitar que la clonación cada vez que realice una alteración, que puede ser costoso.

Si realmente desea salir de Java mutación en tierra (por ejemplo, tal vez usted está manteniendo estos HashMaps existido por mucho tiempo y no quieren Java llama por todo el lugar, o si necesita serializarlos través print y read, o si desea trabajar con ellos de una manera segura para los subprocesos mediante el Clojure STM) se puede convertir entre HashMaps Java y Clojure hash mapas con bastante facilidad, ya que las estructuras de datos de Clojure implementan las interfaces Java adecuados para que puedan hablar el uno al otro .

user> (java.util.HashMap. {:foo :bar})
#<HashMap {:foo=:bar}>

user> (into {} (java.util.HashMap. {:foo :bar}))
{:foo :bar}

Si desea una cosa do similar que devuelve el objeto que está trabajando una vez que haya terminado de trabajar en él, puede utilizar doto. De hecho, un HashMap de Java se utiliza como ejemplo en la documentación oficial para esta función, que es otro indicio de que no es el fin del mundo si utiliza objetos Java (juiciosamente).

clojure.core/doto
([x & forms])
Macro
  Evaluates x then calls all of the methods and functions with the
  value of x supplied at the front of the given arguments.  The forms
  are evaluated in order.  Returns x.

  (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))

Algunas estrategias posibles:

  1. Limite su mutación y los efectos secundarios a una sola función, si puede. Si su función siempre devuelve el mismo valor dado las mismas entradas, se puede hacer lo que quiera internamente. A veces, la mutación de una matriz o mapa es la forma más eficiente o más fácil de implementar un algoritmo. Todavía se podrá disfrutar de los beneficios de la programación funcional, siempre y cuando no se "fuga" efectos secundarios en el resto del mundo.

  2. Si los objetos van a estar allí por un tiempo o que necesitan para jugar muy bien con otro código Clojure, tratar de conseguir que en las estructuras de datos de Clojure tan pronto como sea posible, y los echó de nuevo en HashMaps Java en el último segundo (cuando se alimenta de nuevo a Java).

Es totalmente ACEPTAR para usar el java hash mapa en la forma tradicional.
(do (. m put "key" "value") m)
This is not idiomatic Clojure code, plus I'm modifying m instead of creating a new map.

De la modificación de una estructura de datos que realmente está destinado a ser modificado. Java hash del mapa carece de la estructura compartir que permite Clojures del mapa para ser eficiente copiado.El general idiomáticas manera de hacer esto es usar java-interoperabilidad de funciones para trabajar con java estructuras en el típico java manera, o a limpiamente convertirlos en Clojure estructuras y trabajar con ellos en el funcional Clojure manera.A menos, claro, que hace la vida más fácil y los resultados en un mejor código;a continuación, todas las apuestas están apagadas.

Esto es código que escribí usando HashMaps cuando yo estaba tratando de comparar características de memoria de la versión clojure contra de java (sino que se utiliza desde clojure)

(import '(java.util Hashtable))
(defn frequencies2 [coll]
    (let [mydict (new Hashtable)]
      (reduce (fn [counts x]
            (let [y (.toLowerCase x)]
              (if (.get mydict y)
            (.put mydict y (+ (.get mydict y) 1))
            (.put mydict y 1)))) coll) mydict))

Este es tomar alguna colección y volver cuantas veces (digamos una palabra de una cadena) se reutiliza cada cosa diferente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top