clojure - microsoft - visual studio installer
¿Es posible usar el formulario de caso de Clojure con una enumeración de Java? (3)
Podría usar use un cond en el nombre de la enumm
(case (.name myEnumValue) "NAME_MY_ENUM" (println "Hey, it works!"))
Me parece muy simple en comparación con las alternativas
El doc del case
dice
A diferencia de cond y condp, case hace un despacho de tiempo constante ... Todo tipo de expresiones constantes son aceptables en el caso.
Me gustaría aprovechar el despacho de tiempo constante de Case para que coincida con las enumeraciones de Java. La declaración de switch
de Java funciona bien con enumeraciones, pero haciendo lo siguiente en Clojure:
(defn foo [x]
(case x
java.util.concurrent.TimeUnit/MILLISECONDS "yes!"))
(foo java.util.concurrent.TimeUnit/MILLISECONDS)
Resultados en: IllegalArgumentException No matching clause: MILLISECONDS
¿Las enumeraciones no son compatibles por case
? ¿Estoy haciendo algo mal? ¿Debo recurrir a cond
o hay una mejor solución?
Aquí hay una solución más simple que solo usa la verificación de igualdad en los casos:
(defn cases [v & args]
(let [clauses (partition 2 2 args)]
(some #(when (= (first %) v) (second %)) clauses)))
=> (cases EventType/received EventType/send "A" EventType/received "B")
=> "B"
El problema aquí es que las constantes de prueba del case
, como se describe en los documentos, "deben ser literales en tiempo de compilación". Por lo tanto, en lugar de resolver java.util.concurrent.TimeUnit/MILLISECONDS
, se está java.util.concurrent.TimeUnit/MILLISECONDS
el símbolo literal ''java.util.concurrent.TimeUnit/MILLISECONDS
.
(foo java.util.concurrent.TimeUnit/MILLISECONDS) ; IllegalArgumentException
(foo ''java.util.concurrent.TimeUnit/MILLISECONDS) ; yes!
En cambio, la solución es despachar en el .ordinal
de la instancia de Enum
, que es lo que hace Java al compilar sentencias de switch
sobre enumeraciones:
(defn foo [x]
(case (.ordinal x)
2 "yes!"))
Puede envolver este patrón en una macro que evalúa correctamente los ordinales del caso para usted:
(defmacro case-enum
"Like `case`, but explicitly dispatch on Java enum ordinals."
[e & clauses]
(letfn [(enum-ordinal [e] `(let [^Enum e# ~e] (.ordinal e#)))]
`(case ~(enum-ordinal e)
~@(concat
(mapcat (fn [[test result]]
[(eval (enum-ordinal test)) result])
(partition 2 clauses))
(when (odd? (count clauses))
(list (last clauses)))))))