Тестирование того, является ли объект примитивным массивом Java в Clojure
Какой лучший способ определить, является ли объект примитивным массивом Java в Clojure?
Причина, по которой мне это нужно, - сделать некоторую специальную обработку для примитивных массивов, которая может выглядеть примерно так:
(if (byte-array? object)
(handle-byte-array object))
Это в довольно чувствительной к производительности части кода, поэтому я предпочел бы избежать отражения, если это вообще возможно.
Ответы
Ответ 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
но любой из этих подходов, скорее всего, не станет узким местом в производительности.