2010-05-12 15 views
6

Data un'istanza di una classe, si può ovviamente tornare il suo nome:Scala: ricevendo il nome della classe il tratto è mescolato in

trait MixedInClassDiscovery { 
    val className = this.getClass.getName 
} 

class AClass extends MixedInClassDiscovery { 
    ... 
    this.className // returns "AClass" 
    ... 
} 

Ma in questo modo utilizza la riflessione, una volta per ogni istanza di AClass. Lo stesso può essere fatto una volta per ogni classe, invece?

Una soluzione che viene in mente è quella di combinarlo in oggetti complementari anziché in classi.

risposta

1

non riesco a pensare a un modo per farlo senza spese extra. Si potrebbe fare con gli oggetti da compagnia, tuttavia, e un paio di pezzi in più di lavoro:

object Example { 
    trait Discovery { 
    def companion: Discovered 
    def className: String = companion.className 
    } 
    trait Discovered extends Discovery { 
    override lazy val className = { 
     println("Getting class name!") // To see how many times we're called 
     this.getClass.getSuperclass.getName 
    } 
    } 
    class Test extends Discovery { 
    def companion = Test 
    } 
    object Test extends Test with Discovered {} 
} 

E qui vediamo che questo funziona:

scala> val a = new Example.Test 
a: Example.Test = [email protected] 

scala> val b = a.className 
Getting class name! 
b: String = Example$Test 

scala> val c = a.className 
c: String = Example$Test 

ma giunge in piuttosto un prezzo: si è necessario non solo decorare la classe con Discovery, ma anche implementare il metodo companion e scrivere l'oggetto companion (che non ha necessariamente lo stesso nome, incidentalmente) per ogni classe.

1

Si può fare con il mio modello pimp my lib. Crea una conversione implicita da AnyRef ad es. ClassNameAdder. Ma non è consigliabile creare una conversione implicita a questo livello della gerarchia di tipi.

In ogni caso ecco che arriva il codice:

scala> class ClassNameAdder(ref: AnyRef) { def className = ref.getClass.getName } 
    defined class ClassNameAdder 

scala> implicit def anyref2classnameadder(ref: AnyRef) = new ClassNameAdder(ref: AnyRef) 
anyref2classnameadder: (ref: AnyRef)ClassNameAdder 

scala> "foo".className 
res6: java.lang.String = java.lang.String 

scala> new Object().className 
res7: java.lang.String = java.lang.Object 

scala> List(1,2,3).className 
res8: java.lang.String = scala.collection.immutable.$colon$colon 

scala> class MyClass 
defined class MyClass 

scala> val myClass = new MyClass 
myClass: MyClass = [email protected] 

scala> myClass.className 
res9: java.lang.String = MyClass 
+0

No, questo codice esegue ancora una chiamata di riflessione per ogni istanza. In realtà, per ogni chiamata di 'className', anche se questo può essere risolto in modo banale. –

Problemi correlati