2010-05-12 79 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