Ich fand es überraschend schwierig, ein Makro zu definieren, um die Fehlerbehandlung in beiden clj und cljs zu definieren. Ich nahm an, dass es eine einfache Sache war, Exception
mit js/Error
auszutauschen, aber es stellte sich als komplizierter heraus.Fehlerbehandlung in cljc Makro
Zuerst habe ich versucht, dies:
(defmacro my-macro
[& forms]
`(try
[email protected]
(catch #?(:clj Exception :cljs js/Error) e#
,,,)))
Aber das erzeugt Exception
jedes Mal. Ich erkannte bald, dass das Problem war, dass das Makro während der Kompilierung meiner cljs Dateien aufgerufen wurde, die in einer clj Umgebung geschieht. Daher müsste das Makro ein Formular zurückgeben, das zur Laufzeit in die korrekte Ausnahmeklasse aufgelöst wird. Ich versuchte dies:
(def exception-class
#?(:clj Exception :cljs js/Error))
(defmacro my-macro
[& forms]
`(try
[email protected]
(catch exception-class e#
,,,)))
Jetzt ist es in cljs arbeitete, aber nicht in CLJ !!! Nach einigen Experimenten entdeckte ich, dass JVM Clojure (anscheinend) nicht erlaubt, indirekt auf die Ausnahmeklasse zu verweisen. Sie müssen sich direkt auf den Namen Exception
beziehen.
So schließlich, ließ ich mich auf diese:
(def fake-java
#?(:cljs (clj->js {:lang {:Exception js/Error}})))
(defmacro my-macro
[& forms]
`(let [~'java fake-java]
(try
[email protected]
(catch Exception e#
,,,))))
Exception
zu java.lang.Exception
erweitert, die jetzt auf die richtige Ausnahmeklasse löst sowohl in CLJ zur Laufzeit und cljs.
Meine Frage ist, gibt es einen besseren Weg dazu? Und warum erlaubt es JVM Clojure nicht, indirekt auf die Ausnahmeklasse zu verweisen, aber ClojureScript?
aktualisiert
Mit ClojureMostly Hilfe habe ich das Makro wie dieser Refactoring, und es funktioniert:
(defmacro my-macro
[& forms]
`(try
[email protected]
(catch ~(if (:ns &env) 'js/Error 'Exception) e#
,,,)))
Sie haben die Definition von 'if-cljs' weggelassen, was der wichtigste Teil ist! Was sie hier machen, ist, dass sie je nach Umgebung ein komplett anderes "try/catch" Formular zurückgeben, was ich nicht machen wollte. Mit einigen Optimierungen macht '(: ns & env)' genau das, was ich brauche. Ich werde meine Frage mit dem neuen Code aktualisieren. – grandinero
Sorry, ich habe meine Antwort bearbeitet. – ClojureMostly
Ich nehme an, dass (nach ': ns' key in' & env') funktioniert heute, und könnte sogar morgen arbeiten. Aber es gibt absolut keine Garantie, dass es funktioniert. Wenn Sie diese Lösung implementieren, ist es wichtig zu wissen, dass Sie sich auf "undokumentiertes Verhalten" verlassen. –