给出以下代码:
(map Integer/parseInt ["1" "2" "3" "4"])
除非我将Integer/parseInt
包装在匿名函数中并手动调用(#(Integer/parseInt %)
),否则为什么会出现以下异常?
clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: Unable to find static field: parseInt in class java.lang.Integer
答案 0 :(得分:19)
java interop上的文档说明如下:
用于访问字段或方法成员的首选惯用表单 如上所述。实例成员表单适用于两个字段和 方法。 instanceField表单是字段和必需字段的首选 如果同时存在同名字段和0参数方法。他们 全部扩展到点运算符的调用(如下所述) 宏观扩张时间。扩展如下: ... (类名称/ STATICMETHOD args *)==> (.Classname staticMethod args *)Classname / staticField ==> (.Classname staticField)
所以你应该记住,Class/fieldName
只是获取静态字段的糖,既不是静态方法调用,也不是引用静态方法(java方法实际上不是clojure函数),因此parseInt
中没有静态字段Integer class
,而(Class/fieldName arg)
调用静态方法,它们是两个完全不同的操作,使用类似的含糖语法。
所以当你(map #(Integer/parseInt %) ["1" "2" "3" "4"])
时,它会扩展为
(map #(. Integer parseInt %) ["1" "2" "3" "4"])
(你可以通过宏扩展轻松看到它),
和(map Integer/parseInt ["1" "2" "3"])
扩展为
(map (. Integer parseInt) ["1" "2" "3"])
当它试图获得一个字段(你认为它正在获取对方法的引用)时失败。
答案 1 :(得分:5)
users
是Integer/parseInt
类的静态方法,而不是clojure函数。每个clojure函数都编译为实现Integer
接口的java类。 clojure.lang.IFn
期望clojure函数(实现map
接口)作为第一个参数,但IFn
不是。
您可以在clojure repl。
中查看Integer/parseInt
或许阅读this stackoverflow question可以帮助您了解正在发生的事情。
答案 2 :(得分:1)
您可能更喜欢在没有Java互操作的情况下执行此操作:
(map read-string ["1" "2"])
或更安全的变体:
(map clojure.edn/read-string ["1" "2"])
我个人更喜欢在Clojure代码中尽量减少使用Java。
至于为什么你不能只传递Java函数,因为map
期望Clojure中的函数,而不是Java中的函数。