Подтвердить что ты не робот

Тестирование того, является ли объект примитивным массивом Java в Clojure

Какой лучший способ определить, является ли объект примитивным массивом Java в Clojure?

Причина, по которой мне это нужно, - сделать некоторую специальную обработку для примитивных массивов, которая может выглядеть примерно так:

  (if (byte-array? object)
    (handle-byte-array object))

Это в довольно чувствительной к производительности части кода, поэтому я предпочел бы избежать отражения, если это вообще возможно.

4b9b3361

Ответ 1

вы можете использовать отражение один раз, чтобы получить класс от имени, кешируйте это, а затем сравните остальные с тем, что

(def array-of-ints-type (Class/forName "[I"))
(def array-of-bytes-type (Class/forName "[B")) 
...

(= (type (into-array Integer/TYPE [1 3 4])) array-of-ints-type)
true

Ответ 2

(defn primitive-array? [o]
  (let [c (class o)]
    (and (.isArray c)
         (.. c getComponentType isPrimitive))))

В некоторых случаях вы можете использовать что-то вроде следующего:

(defn long-array? [o]
  (let [c (class o)]
    (and (.isArray c)
         (identical? (.getComponentType c) Long/TYPE))))

Ответ 3

Чтобы проверить массив байтов без использования отражения, вы можете сделать это:

(def ^:const byte-array-type (type (byte-array 0)))
(defn bytes? [x] (= (type x) byte-array-type))

Не совсем понятно, почему, но вы можете даже встроить тип байтового массива с помощью ^:const.

Ответ 4

Или простой старый instance?:

(instance? (RT/classForName "[B") thing)

Ответ 5

Как указал Артур Ульфельдт, вы можете использовать Class/forName, например, как здесь:

(def byte_array_class (Class/forName "[B"))

(defn byte-array? [arr] (instance? byte_array_class arr))

Если вы хотите избежать магических строк типа "[B" при кешировании классов, вы можете применить class к существующему объекту массива:

(def byte_array_class (class (byte-array [])))

Ответ 6

Подкрепляет все остальные ответы. Здесь он как однострочный:

(def byte-array? (partial instance? (Class/forName "[B")))

Для других примитивов обратитесь к http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getName%28%29 (или спецификации java). Или просто сделайте то, что предлагает Геррит, (type (xyz-array 0)). В частности, вы можете использовать:

"[Z" boolean array
"[B" byte array
"[C" char array
"[D" double array
"[F" float array
"[I" integer array
"[J" long array
"[S" short array

Поскольку производительность была упомянута, здесь приведен небольшой результат теста (time (dotimes [_ 500000] (byte-array? x))) и с byte-array-class def'd

(def byte-array? (partial instance? (Class/forName "[B")))
78.518335 msecs
(defn byte-array? [obj] (instance? byte-array-class obj))
34.879537 msecs
(defn byte-array? [obj] (= (type obj) byte-array-class))
49.68781 msecs

instance? vs type= instance? победы

partial vs defn= defn wins

но любой из этих подходов, скорее всего, не станет узким местом в производительности.