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?
- You can do pattern matching on it,
- You can construct instances of these classes without using the new keyword,
- All constructor arguments are accessible from outside using automatically generated accessor functions,
- The toString method is automatically redefined to print the name of the case class and all its arguments,
- The equals method is automatically redefined to compare two instances of the same case class structurally rather than by identity.
- 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.