2009-12-16 125 views
22

我需要由字符串名稱定義的對象(或「單例對象」或「伴隨對象」......除了類之外的任何東西)。換句話說,如果我有:在scala中通過字符串名稱獲取對象實例

package myPackage 
object myObject 

...那麼有沒有這樣的事:

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

回答

12

斯卡拉仍然缺少一個反射API。

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) 

爲了讓無類型的同伴對象,你可以直接使用類:

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) 

這取決於途中階可以通過加載同伴對象類得到同伴對象的一個​​實例映射到java類。

+1

聖牛。你知道這個語法是否是Scala規範的固定部分(與語言中的其他任何東西一樣固定)?依靠這個似乎是一個糟糕的主意。因爲我的目標是讓代碼更清晰* ...謝謝! – Dave 2009-12-17 11:24:32

+0

正如他所提到的,Scala中沒有反射API,所以無論是否包含Scala規範,這都是您執行此操作的唯一方法。 我注意到這個問題/答案已經過了一年多了,這裏有什麼消息嗎? – pdinklag 2011-02-17 05:37:00

1

禁止反射技巧,你不能。請注意,例如,如何在Scala 2.8集合上定義方法companion - 它就在那裏,因此一個類的實例可以獲得伴隨對象,否則這是不可能的。

+0

您可以添加一個鏈接到源代碼嗎? – 2009-12-16 12:11:02

+0

http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala,儘管如此,希望2.8的Scaladoc 2很快會包含源代碼的鏈接,就像已經發生在2.7中一樣。 – 2009-12-17 11:24:00

11

對托馬斯榮格的回答進行調整:你會更好地說同伴[List.type],因爲a)這應該是一個穩定的方式來引用它,而不是依賴於名稱修改方案和b)你得到未消除的類型。

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

非常好!對我的口味來說還是有點不習慣,但我可以用這個...... – Dave 2010-01-12 01:18:40

+0

這比List.make(3,「a」)更好嗎? OP想要按字符串名稱獲取對象 – IttayD 2010-11-07 12:51:37

+1

謝謝!這正是我所期待的。這當然是一種黑客攻擊,但比我設想的要骯髒。 – 2011-06-27 14:19:02

34

在斯卡拉2.10,我們可以這樣做

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)