2011-09-23 20 views

Respuesta

2

Actualmente (2011), se puede utilizar la reflexión para averiguar si la clase implementa la interfaz 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 

Esto es sólo una aproximación - que podría ir más allá y comprobar si se dispone de un método copy, si implementa Serializable, si tiene un objeto complementario con un método apropiado apply o unapply - en esencia, verifique todas las cosas esperadas de una clase de caso mediante reflexión.

El paquete de reflexión scala que viene en uno de los próximos lanzamientos debe hacer que la detección de clases de casos sea más fácil y más precisa.

EDIT:

Ahora puede hacerlo utilizando la nueva biblioteca Reflexión Scala - ver otra respuesta.

+0

Gracias, axel22. Esta es una solución a mi problema. Espero que los desarrolladores agreguen este método de Scala lo antes posible. Сlass implementa la interfaz scala.Product - ¿esta es una condición suficiente para ello? – DimParf

+0

No, no hay condiciones suficientes para verificar esto (afaik).No se puede verificar la existencia de un modificador 'case' en el código original, solo para los métodos que se generan debido al modificador' case '. Como escribí anteriormente, todo es solo una aproximación. – axel22

2

Si quiere decir: ¿Puedo determinar si una clase es una clase de caso o una clase sin caso mediante programación, la respuesta es no, pero puede hacer una aproximación. Las clases de casos son solo un truco de compilación, le dicen al compilador que cree ciertos métodos, etc. En el código de bytes final, no hay diferencia entre clases normales y clases de casos.

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

  1. Puede hacer comparación de patrones en él,
  2. puede construir instancias de estas clases sin necesidad de utilizar el nuevo palabra clave,
  3. Todos los argumentos del constructor son accesibles desde el exterior utilizando funciones de acceso generadas automáticamente,
  4. El método toString se redefine automáticamente para imprimir el nombre de la clase de caso y todos sus argumentos,
  5. El método equals se redefine automáticamente para comparar dos instancias de de la misma clase de caso estructuralmente que por identidad.
  6. El método hashCode se redefine automáticamente para utilizar los hashCodes de los argumentos del constructor.

Así que en realidad se puede crear una clase de caso con sólo definir los métodos correctos & compañero yourself.

Para una idea sobre cómo averiguar si una clase podría ser una clase de caso, consulte la respuesta de axel22.

16

Utilizando la nueva Scala reflexión 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 
Cuestiones relacionadas