Dieses Verhalten ergibt für mich keinen Sinn:
%Vor% Warum findet der (BigDecimal. (Long. 1))
-Fall keine eindeutige übereinstimmende Methodensignatur, während die anderen beiden Ausdrücke - die genau den gleichen Argumenttyp haben - erfolgreich sind?
Was ich an diesem Verhalten sogar mehr seltsam finde, ist, dass es dem Long
-Typ besonders ähnelt:
Aus dieser Diskussion in der Clojure-Diskussionsgruppe scheint es, als wären Sie schon einmal begegnet eine Designentscheidung von Rich Hickey. Da BigDecimal keinen Konstruktor der Signatur BigDecimal(Long long)
(Edit: ) hat und der Compiler daher zwischen den Konstruktoren int
und long
wählen muss, lesen Sie die Kommentare unten Warum verwendet Integer
), wird der Compiler nicht versuchen, zu "erraten", welcher Konstruktor gemeint ist, und explizit fehlschlägt.
Die Quintessenz ist, dass bestimmte Typanforderungen auf der Java-Seite explizites Boxen erfordern, um korrekten und nicht spröden Code zu haben. - Rich Hickey
Beachten Sie, dass Literale als Primitive, nicht als "Boxed" -Typen geparsed werden, pro diese Dokumentation :
Im Gegensatz zu früheren Versionen von Clojure werden numerische Literale als primitive Longs oder Doubles analysiert.
Um zu verstehen, warum die anderen Operationen funktionieren, müssen Sie in die Clojure-Quelle eintauchen, insbesondere Compiler.java
und ihre innere Klasse NumberExpr
. Das ist die Stelle, an der Ihr Literal automatisch in ein Long
umgewandelt wird und der Compiler kein Problem hat, indem er Object.getClass()
aufruft (was sowohl type
als auch class
tun).
In der Compiler.getMatchingParams()
versucht der Clojure-Compiler, den zu verwendenden Konstruktor von BigDecimal
aufzulösen. Sie haben jedoch explizit angegeben, dass Ihr Parameter den Typ Long
hat - es gibt keinen Konstruktor für BigDecimal, der diesen Typ verwendet.
Vielleicht ist das kein "gesunder Menschenverstand", aber Rich Hickey hat die Entscheidung getroffen, dass Sie genau über den Typ Ihrer Parameter Bescheid wissen müssen und dass sie dem Typ der Java-Klasse entsprechen müssen. Der Compiler weigert sich, Ihre Absicht zu erraten.
Beachten Sie Folgendes:
%Vor% Beachten Sie auch, dass dieser Java-Code gültig ist und in den Konstruktor int
für BigDecimal aufgelöst wird:
Aber dieser Code schlägt auch fehl (obwohl er den int
-Konstruktor verwenden sollte):
tl; dr: Clojure unterstützt Java interop , aber das bedeutet nicht, dass es den Regeln der Java-Sprachspezifikation folgen muss.
Was ist mit cast
?
Ein Kommentar unten fragt nach (cast)
. In diesem Fall weisen Sie den Clojure-Compiler explizit an, die Typauflösung an die JVM zu delegieren. Beachten Sie den folgenden (unsinnigen) Code, der kompiliert, aber zur Laufzeit nicht ausgeführt wird:
Epilog II
In der Clojure-Community gab es eine ganze Reihe von Diskussionen zu diesem Thema. Bitte überprüfen Sie diese detaillierten Themen:
Verbesserte primitive Unterstützung (Rich Hickey)
Clojure 1.3 Behandlung von ganzen Zahlen und Longs (Nathan Marz)
BigDecimal hat keinen Konstruktor für Long,
BigDecimal (BigInteger val)
%Vor%BigDecimal (BigInteger unscaledVal, Skalierung int)
%Vor%BigDecimal (doppelter Wert)
%Vor%BigDecimal (Zeichenfolge val)
%Vor% Es ist unklar, welche dieser (Long. 1)
übereinstimmt. Die Funktion clojure.core.bigdec
arbeitet an dieser Eingabe, indem sie ihre Eingabe an BigDec/valueOf
übergibt, um das BigDecimal
verwendet diesen Aufruf:
%Vor%