2009-12-16 123 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)