测试对象是否是Clojure中的Java基元数组



在Clojure中检测对象是否是Java基元数组的最佳方法是什么?

我需要这样做的原因是对基元数组进行一些特殊处理,它可能看起来像:

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

它在一段对性能相当敏感的代码中,所以如果可能的话,我宁愿避免反思。

您可以使用反射一次从名称中获取类,缓存它,然后将其余部分与进行比较

(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
(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))))

要在不使用反射的情况下检查字节数组,可以执行以下操作:

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

不完全确定原因,但您甚至可以使用^:const内联字节数组类型。

正如Arthur Ulfeldt所指出的,您可以使用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 [])))

或普通旧instance?:

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

支持所有其他答案。这是一条单行线:

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

有关其他基元,请参阅http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getName%28%29(或java规范)。或者按照Gerrit的建议使用(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 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=实例?赢得

partial vs defn=defn赢得

但这些方法中的任何一种都可能不会成为性能的瓶颈。

由于Clojure 1.9,您可以使用bytes?字节吗?文档链接

相关内容

  • 没有找到相关文章

最新更新