Testing whether an object is a Java primitive array in Clojure

前端 未结 7 2279
时光说笑
时光说笑 2021-02-08 08:47

What\'s the best way to detect whether an object is a Java primitive array in Clojure?

The reason I need this is to do some special handling for primitive arrays, which

相关标签:
7条回答
  • 2021-02-08 09:05
    (defn primitive-array? [o]
      (let [c (class o)]
        (and (.isArray c)
             (.. c getComponentType isPrimitive))))
    

    For particular cases, you could use something like the following:

    (defn long-array? [o]
      (let [c (class o)]
        (and (.isArray c)
             (identical? (.getComponentType c) Long/TYPE))))
    
    0 讨论(0)
  • 2021-02-08 09:13

    To check for a byte array without the use of reflection you can do this:

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

    Not exactly sure why, but you can even inline the byte-array-type with ^:const.

    0 讨论(0)
  • 2021-02-08 09:14

    Or plain old instance?:

    (instance? (RT/classForName "[B") thing)
    
    0 讨论(0)
  • 2021-02-08 09:22

    Props to all the other answers. Here it is as a one-liner:

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

    For other primitives, refer to http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getName%28%29 (or the java spec). Or just do what Gerrit suggests with (type (xyz-array 0)). Specifically you can use:

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

    Since performance was mentioned, here's a small benchmark result of running (time (dotimes [_ 500000] (byte-array? x))), and with 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? wins

    partial vs defn = defn wins

    but any of these approaches will likely not be a bottleneck in performance.

    0 讨论(0)
  • 2021-02-08 09:23

    you can use reflection once to get the class from the name, cache this and then compare the rest to that

    (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
    
    0 讨论(0)
  • 2021-02-08 09:23

    As pointed by Arthur Ulfeldt, you can use Class/forName, for example, like here:

    (def byte_array_class (Class/forName "[B"))
    
    (defn byte-array? [arr] (instance? byte_array_class arr))
    

    If you want to avoid magic strings like "[B" when caching the classes, you can apply class to an existing array object:

    (def byte_array_class (class (byte-array [])))
    
    0 讨论(0)
提交回复
热议问题