2009-12-16 10 views
22

Ho bisogno dell'oggetto (o "oggetto singleton" o "oggetto companion" ... qualsiasi cosa tranne la classe) definito da un nome di stringa. In altre parole, se ho:Ottenere istanza di oggetto per nome stringa in scala

package myPackage 
object myObject 

... allora c'è qualcosa di simile:

GetSingletonObjectByName("myPackage.myObject") match { 
    case instance: myPackage.myObject => "instance is what I wanted" 
} 

risposta

12

Scala manca ancora un'API di riflessione. È possibile ottenere l'un'istanza dell'oggetto compagna caricando la classe compagno di oggetto:

import scala.reflect._ 
def companion[T](implicit man: Manifest[T]) : T = 
    man.erasure.getField("MODULE$").get(man.erasure).asInstanceOf[T] 


scala> companion[List$].make(3, "s") 
res0: List[Any] = List(s, s, s) 

Per ottenere il compagno non tipizzata oggetto è possibile utilizzare la classe direttamente:

import scala.reflect.Manifest 
def companionObj[T](implicit man: Manifest[T]) = { 
    val c = Class.forName(man.erasure.getName + "$") 
    c.getField("MODULE$").get(c) 
} 


scala> companionObj[List[Int]].asInstanceOf[List$].make(3, "s") 
res0: List[Any] = List(s, s, s) 

Questo dipende dal modo in cui Scala è mappato alle classi java.

+1

Porca vacca. Sai se questa sintassi è una parte fissa delle specifiche di Scala (fissate come qualsiasi altra cosa nella lingua, comunque)? Sembra una cattiva idea affidarsi a questo. E poiché il mio obiettivo era quello di rendere il codice * più chiaro * ... Grazie! – Dave

+0

Come già accennato, non ci sono ancora API di riflessione in Scala, quindi se questo è coperto dalle specifiche di Scala o meno, questo è l'unico modo per farlo. Ho notato che questa domanda/risposta ha più di un anno, ci sono novità qui? – pdinklag

1

Riflessioni con trucchi di riflessione, non è possibile. Si noti, ad esempio, come il metodo companion è definito sulle raccolte Scala 2.8: è lì così un'istanza di una classe può ottenere l'oggetto associato, che altrimenti non è possibile.

+0

Potresti aggiungere un link alla fonte, per favore? –

+0

http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala, tuttavia, si spera che lo Scaladoc 2 di 2.8 contenga presto collegamenti alla sorgente, come già accade con 2.7. –

11

Adeguamento alla risposta di Thomas Jung sopra: si farebbe meglio a dire compagno [List.type] perché a) questo dovrebbe essere un modo stabile per riferirsi ad esso, non dipende dalla schema di pressare nome e b) si ottiene il tipi non registrati.

def singleton[T](implicit man: reflect.Manifest[T]) = { 
    val name = man.erasure.getName() 
    assert(name endsWith "$", "Not an object: " + name) 
    val clazz = java.lang.Class.forName(name) 

    clazz.getField("MODULE$").get(clazz).asInstanceOf[T] 
} 

scala> singleton[List.type].make(3, "a")      
res0: List[java.lang.String] = List(a, a, a) 
+0

Molto bello! Ancora un po 'traballante per i miei gusti, ma posso usare questo ... – Dave

+0

Com'è meglio di "List.make (3," a ")'? L'OP voleva ottenere l'oggetto con il nome della stringa – IttayD

+1

Grazie! Questo e 'esattamente quello che stavo cercando. È certamente un hack, ma meno sporco di quello che sono riuscito a inventare. –

34

a Scala 2.10 si può fare in questo modo

import scala.reflect.runtime.universe 

val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader) 

val module = runtimeMirror.staticModule("package.ObjectName") 

val obj = runtimeMirror.reflectModule(module) 

println(obj.instance) 
Problemi correlati