2013-12-12 5 views
5

clojureのjava float配列でインスタンスメソッドを使用しようとすると、いくつか問題が発生します。具体的には、次のコードは、私の理解では.lengthプリミティブ配列でのClojure - 反射警告.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への呼び出しを解決するための反射の必要性を排除する必要があります。私は何が欠けていますか?

答えて

9

JVM上の配列は通常のオブジェクトとよく似ておらず、長さはフィールドルックアップではなく、専用のオペコードarraylengthによって取得されます。 Javaのarray.length表記法は、このオペコードにコンパイルする構文糖だけです。したがって、(.length fs)は、実行時に単に失敗します。fsにはlengthメソッドもlengthフィールドもありません(実際は配列であると仮定しているため)。

したがって、あなたはclojure.core/alength機能を使用する必要があります型ヒントなしで

(alength fs) 

を、これは反射コールになります。型ヒントを使用すると、fs.length(Java表記)を返す静的メソッドへの直接呼び出しになります。

3

プリミティブ配列は、JVMではやや特殊なケースですが、その長さを取得するためのバイトコード命令があります:arraylengthです。 Clojureが反射警告を表示する理由は、浮動小数点配列のクラス[Fは、名前がlengthのフィールドを宣言していないため、フィールドを取得しようとすると(here)フィールドが存在しないためです。

あなた自身が次のことをやって、それを確認することができます。

(-> (float-array [1]) 
    class 
    (.getField "length")) 
関連する問題