How to programmatically determine if the class is

2019-04-04 18:33发布

问题:

How to programmatically determine if the given class is a case class or a simple class?

回答1:

Currently (2011), you can use reflection to find out if the class implements the interface scala.Product:

scala> def isCaseClass(o: AnyRef) = o.getClass.getInterfaces.find(_ == classOf[scala.Product]) != None
isCaseClass: (o: AnyRef)Boolean

scala> isCaseClass(Some(1))
res3: Boolean = true

scala> isCaseClass("")
res4: Boolean = false

This is just an approximation - you could go further and check if it has a copy method, if it implements Serializable, if it has a companion object with an appropriate apply or unapply method - in essence, check for all the things expected from a case class using reflection.

The scala reflection package coming in one of the next releases should make case class detection easier and more precise.

EDIT:

You can now do it using the new Scala Reflection library -- see other answer.



回答2:

Using new Scala reflection API:

scala> class B(v: Int)
defined class B

scala> case class A(v: Int)
defined class A

scala> def isCaseClassOrWhat_?(v: Any): Boolean = {
     |   import reflect.runtime.universe._
     |   val typeMirror = runtimeMirror(v.getClass.getClassLoader)
     |   val instanceMirror = typeMirror.reflect(v)
     |   val symbol = instanceMirror.symbol
     |   symbol.isCaseClass
     | }
isCaseClassOrWhat_$qmark: (v: Any)Boolean

scala> class CaseClassWannabe extends Product with Serializable {
     |   def canEqual(that: Any): Boolean = ???
     |   def productArity: Int = ???
     |   def productElement(n: Int): Any = ???
     | }
defined class CaseClassWannabe

scala> isCaseClassOrWhat_?("abc")
res0: Boolean = false

scala> isCaseClassOrWhat_?(1)
res1: Boolean = false

scala> isCaseClassOrWhat_?(new B(123))
res2: Boolean = false

scala> isCaseClassOrWhat_?(A(321))
res3: Boolean = true

scala> isCaseClassOrWhat_?(new CaseClassWannabe)
res4: Boolean = false


回答3:

If you mean: Can I determine whether a class is a case class or a non-case class programmatically, the answer is no, but you can do an approximation. Case classes are just a compiler hack, they tell the compiler to create certain methods etc. In the final bytecode, there is no difference between normal classes and case classes.

From How does a case class differ from a normal class?

  1. You can do pattern matching on it,
  2. You can construct instances of these classes without using the new keyword,
  3. All constructor arguments are accessible from outside using automatically generated accessor functions,
  4. The toString method is automatically redefined to print the name of the case class and all its arguments,
  5. The equals method is automatically redefined to compare two instances of the same case class structurally rather than by identity.
  6. The hashCode method is automatically redefined to use the hashCodes of constructor arguments.

So you can actually create a case class by just defining the correct methods & companion objects yourself.

For an idea as to how to find out if a class could be a case class, look at the answer from axel22.



标签: class scala