Clojure - 原始数组.length的反射警告

时间:2013-12-12 05:22:23

标签: clojure primitive

我在使用clojure中的java float数组上的实例方法时遇到了一些麻烦。具体来说,以下代码在调用.length

时给出了反射警告
(defn make-matrix
  ([^floats fs]
   (let [len-fs (.length fs)]
     (cond (>= len-fs 16) (Matrix4. fs)
           (>= len-fs 9)  (Matrix3. fs)
           :else (throw (IllegalArgumentException. (str "Array must have at least 9 elements (found" len-fs ")")))))))

根据我的理解,类型提示应该不需要反射来解析对.length的调用。我错过了什么?

2 个答案:

答案 0 :(得分:10)

JVM上的数组不像常规对象,它们的长度不是通过字段查找获得的,而是通过专门的操作码arraylength获得的。 Java的array.length表示法只是语法糖,可编译为此操作码。因此,(.length fs)将在运行时失败,因为fs将既没有length方法也没有length字段(假设它实际上是一个数组)

因此,您应该使用clojure.core/alength函数:

(alength fs)

没有类型提示,这将导致反射调用;使用类型提示,它将直接调用返回fs.length的静态方法(用Java表示法)。

答案 1 :(得分:3)

原始数组在JVM中是一种特殊情况,证明了这一点是有一个字节码指令来获取它们的长度:arraylength。所以Clojure显示反射警告的原因是因为浮点数组[F的类没有声明名为length的字段,所以当它尝试获取它时here这个领域不存在。

您可以自行检查以下内容:

(-> (float-array [1])
  class
  (.getField "length"))