Clojure: Unable to find static field

…衆ロ難τιáo~ 提交于 2019-12-23 06:56:58

问题


Given the following piece of code:

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

Why do I get the following exception unless I wrap Integer/parseInt in an anonymous function and call it manually (#(Integer/parseInt %))?

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

回答1:


the documentation on java interop says the following:

The preferred idiomatic forms for accessing field or method members are given above. The instance member form works for both fields and methods. The instanceField form is preferred for fields and required if both a field and a 0-argument method of the same name exist. They all expand into calls to the dot operator (described below) at macroexpansion time. The expansions are as follows: ... (Classname/staticMethod args*) ==> (. Classname staticMethod args*) Classname/staticField ==> (. Classname staticField)

so you should remember, that Class/fieldName is just a sugar for getting a static field, neither static method call, nor reference to the static method (java method is not a clojure function really), so there is no static field parseInt in Integer class, while (Class/fieldName arg) calls a static method, they are two totally different operations, using the similar sugary syntax.

so when you do (map #(Integer/parseInt %) ["1" "2" "3" "4"]) it expands to

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

(you can easily see it yourself with macroexpansion),

and (map Integer/parseInt ["1" "2" "3"]) expands to

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

It fails when it is trying to get a field (which you think is getting a reference to a method).




回答2:


Integer/parseInt is a static method of Integer class, not a clojure function. Each clojure function is compiled to java class which implements clojure.lang.IFn interface. map expects clojure function (which implements IFn interface) as a first argument, however, Integer/parseInt is not.

You can check that in the 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

Perhaps reading this stackoverflow question will help you understand what is going on.




回答3:


You might prefer to do it without the Java interop:

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

or for a more safe variant:

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

I personally prefer to minimize the use of Java as much as possible in Clojure code.

As for why you can't just pass the Java function, because map expects a function in Clojure, not a function in Java.



来源:https://stackoverflow.com/questions/35199808/clojure-unable-to-find-static-field

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!