2010-05-12 29 views
6

给定一个类的实例,我们可以明显地回到它的名字:斯卡拉:获取类性状混合的名称

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

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

但是这样使用反射,一旦为AClass每个实例。相反,每个班级都可以做一次吗?

想到的一个解决方案是将其混合到伴侣对象中,而不是类本身。

回答

1

我想不出任何办法,没有额外的开销,做到这一点。你可以与同伴对象做到这一点,但是,和一对夫妇的工作的额外碎片:

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

在这里,我们看到,这个工程:

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 

,但它是在相当的代价:你不仅需要用Discovery来装饰类,还需要实现伴随方法,并为每个类编写伴随对象(顺便提一下,不需要有相同的名字)。

1

你可以用pimp my lib模式来做到这一点。创建从AnyRef到例如ClassNameAdder。但不建议在类型层次结构的这一级创建这种隐式转换。

反正这里来了代码:

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

不,这段代码仍然会为每个实例进行反射调用。实际上,对于每个'className'调用,尽管这可以被平凡地修复。 – 2010-05-12 20:01:57