2010-05-12 9 views
6

Dada una instancia de una clase, podemos obviamente devolver su nombre:Scala: Obtener el nombre de la clase del rasgo se mezcla en

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

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

Pero de esta manera utiliza la reflexión, una vez para cada instancia de AClass. ¿Se puede hacer lo mismo una vez para cada clase?

Una solución que me viene a la mente es mezclarla en objetos complementarios en lugar de clases.

Respuesta

1

No puedo pensar en ninguna manera de hacerlo sin sobrecarga adicional. Se podía hacerlo con objetos de compañía, sin embargo, y un par de piezas extras de trabajo:

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 {} 
} 

Y aquí vemos que esto funciona:

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 

pero viene en lugar de un precio: se No solo debe decorar la clase con Discovery, sino también implementar el método complementario y escribir el objeto complementario (que, por cierto, no tiene por qué tener el mismo nombre) para cada clase.

1

Puedes hacerlo con el patrón pimp my lib. Cree una conversión implícita de AnyRef a p. ClassNameAdder. Pero no se recomienda crear una conversión implícita de este tipo en la jerarquía de tipos.

De todos modos aquí viene el código:

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, este código aún hace una llamada de reflexión para cada instancia. En realidad, para cada llamada 'className', aunque esto puede ser trivialmente corregido. –

Cuestiones relacionadas