2011-09-23 8 views

risposta

2

Attualmente (2011), è possibile utilizzare la reflection per scoprire se la classe implementa l'interfaccia 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 

Questo è solo un'approssimazione - si potrebbe andare oltre e verificare se ha un metodo copy, se implementa Serializable, se ha un oggetto companion con un metodo appropriato apply o unapply, in sostanza, controlla tutti gli aspetti previsti da una classe di casi utilizzando la reflection.

Il pacchetto scala reflection in arrivo in una delle prossime versioni dovrebbe rendere più facile e più preciso il rilevamento della classe del case.

EDIT:

ora è possibile farlo utilizzando la nuova libreria di riflessione Scala - vedi altra risposta.

+0

Grazie, axel22. Questa è una soluzione al mio problema. Spero che gli sviluppatori aggiungano questo metodo di Scala il prima possibile. Сlass implementa l'interfaccia scala.Product - questa è una condizione sufficiente per questo? – DimParf

+0

No, non ci sono condizioni sufficienti per controllare questo (afaik).Non è possibile verificare l'esistenza di un modificatore 'case' nel codice originale, solo per i metodi che vengono generati a causa del modificatore' case'. Come ho scritto sopra, il tutto è solo un'approssimazione. – axel22

2

Se intendi: Posso determinare se una classe è una classe case o una classe non-case programmaticamente, la risposta è no, ma puoi fare un'approssimazione. Le classi di casi sono solo un hack del compilatore, dicono al compilatore di creare determinati metodi, ecc. Nel bytecode finale, non c'è differenza tra classi normali e classi di casi.

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

  1. Si può fare pattern matching su di esso,
  2. si può creare istanze di queste classi senza utilizzare la nuova parola chiave,
  3. Tutti gli argomenti del costruttore sono accessibili dall'esterno tramite funzioni di accesso generate automaticamente,
  4. Il metodo toString viene ridefinito automaticamente per stampare il nome della classe case e tutti i suoi argomenti,
  5. Il metodo di uguaglianza viene ridefinito automaticamente per confrontare due istanze della stessa classe di casi con la stessa classe di casi anziché con l'identità.
  6. Il metodo hashCode viene ridefinito automaticamente per utilizzare gli hash degli argomenti del costruttore.

modo da poter effettivamente creare una classe caso per definire soltanto i metodi corretti & compagno da soli oggetti.

Per un'idea su come scoprire se una classe potrebbe essere una classe di caso, osservare la risposta di axel22.

16

Usando nuova Scala riflessione 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 
Problemi correlati