2010-05-12 3 views
6

Учитывая экземпляр класса, очевидно, можно вернуть его имя:Scala: получение имени класса черта смешивается в

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

Вы можете сделать это с помощью сутенера моего шаблона 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', хотя это может быть тривиально исправлено. –