Vraag Clojure: Kan statisch veld niet vinden


Gezien het volgende stuk code:

(map Integer/parseInt ["1" "2" "3" "4"])

Waarom krijg ik de volgende uitzondering tenzij ik verpak Integer/parseInt in een anonieme functie en noem het handmatig (#(Integer/parseInt %))?

clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: Unable to find static field: parseInt in class java.lang.Integer

10
2018-02-04 11:29


oorsprong


antwoorden:


de documentatie over java interop zegt het volgende:

De idiomatische vormen die de voorkeur hebben voor toegang tot veld- of methode-leden   zijn hierboven gegeven. Het voorbeeldlidformulier werkt voor zowel velden als   methoden. Het exampleField-formulier heeft de voorkeur voor velden en is vereist   als zowel een veld als een 0-argumentmethode met dezelfde naam bestaan. Ze   alle breiden uit naar oproepen naar de puntoperator (hieronder beschreven) bij   macrouitbreidingstijd. De uitbreidingen zijn als volgt:   ...   (Klassenaam / staticMethod   args *) ==> (. Classname staticMethod args *) Classname / staticField ==>   (.Classnaam staticField)

dus dat zou je moeten onthouden Class/fieldName is gewoon een suiker om statisch te worden veld-, noch statisch method call, ook niet verwijzing naar de statische methode (java-methode is niet echt een clojure-functie), dus er is geen statisch veld parseInt in Integer class, terwijl (Class/fieldName arg) roept een statisch methode, het zijn twee totaal verschillende bewerkingen, die dezelfde suikerachtige syntaxis gebruiken.

dus als je dat doet (map #(Integer/parseInt %) ["1" "2" "3" "4"]) het breidt uit naar

(map #(. Integer parseInt %) ["1" "2" "3" "4"]) 

(je kunt het gemakkelijk zelf zien met macro-uitbreiding),

en (map Integer/parseInt ["1" "2" "3"]) breidt uit naar

(map (. Integer parseInt) ["1" "2" "3"])

Het faalt wanneer het probeert een veld te krijgen (waarvan je denkt dat het een verwijzing naar een methode krijgt).


15
2018-02-04 12:06



Integer/parseInt is een statische methode van Integer klasse, geen clojure-functie. Elke clojure-functie is gecompileerd naar de java-klasse die wordt geïmplementeerd clojure.lang.IFn interface. map verwacht clojure-functie (die implementeert IFn interface) als eerste argument, echter, Integer/parseInt is niet.

Je kunt dat controleren in de clojure-repl.

user=> (type map)
clojure.core$map
user=> (type Integer)
java.lang.Class
user=> (type Integer/parseInt)

CompilerException java.lang.RuntimeException: Unable to find static field: parseInt in class java.lang.Integer, compiling:(/private/var/folders/p_/psdvlp_12sdcxq07pp07p_ycs_v5qf/T/form-init4110003279275246905.clj:1:1)

user=> (defn f [] 1)
#'user/f
user=> (type f)
user$f
user=> (type #(1))
user$eval9947$fn__9948

Misschien lezen deze stackoverflowvraag zal je helpen begrijpen wat er aan de hand is.


4
2018-02-04 11:59



Je zou het misschien liever doen zonder de Java-interop:

(map read-string ["1" "2"])

of voor een meer veilige variant:

(map clojure.edn/read-string ["1" "2"])

Persoonlijk geef ik er de voorkeur aan om het gebruik van Java zo veel mogelijk te beperken in Clojure-code.

Wat betreft waarom je niet zomaar de Java-functie kunt passeren, omdat map verwacht een functie in Clojure, geen functie in Java.


1
2018-02-04 11:46