尝试在Scala中动态分配类

时间:2012-10-31 01:38:09

标签: scala dynamic

任何人都知道如何在Scala(2.10)中动态分配类? 我有一些课MyClass。我正在使用Akka(2.0),我真的希望能够做到这样的事情:

classnames = List[String]("fqcn", "fqcn", fqcn"....]
for (name <- classnames) {
     val clazz = classLoader.load(name)
     val actRef = actorSystem.actorOf(Props[clazz])
}

但是,Akka还有其他限制。所以我能做的最好(我认为)是:

val activeClasses = HashMap([String, String, ActorRef]
     ("commonname" -> 
       "Fqcn", actorOf(Props[new classobject]])
  )

其中classobject是文字类,而不是类加载器的名称引用。我确实必须在某处编译类并执行

actorOf(道具[ classobject * * ])

这看起来非常难看 - 是否有更好,更优雅的方式来做到这一点?

3 个答案:

答案 0 :(得分:3)

修复您提供的第一个样本,请参阅注释:

classnames = List[String]("fqcn", "fqcn", "fqcn"....) // close ( with ) not ]
for (name <- classnames) {
     val clazz = classLoader.forName(name) // forName is what loads a class
     //val actRef = actorSystem.actorOf(Props[clazz]) // still wrong I will explain later
}

第二个样本还有一些问题。

首先HashMap([String, String, ActorRef]("commonname" -> "Fqcn", someThing)),它接近正确,但有一些关键的句法错误。

在Scala中,[]用于声明或定义类型参数,看起来我们手头的情况是定义问题,换句话说,我们想说明什么类型的参数。 Scala只允许放置类型参数的几个地方,它是类实例化后的正确类(例如new HashMap[String, Int])和方法调用(例如list.map[String](...)

因此,将类型参数放在HashMap[String, String, ActorRef](...)中将是有效的Scala语法,并且由于HashMap是伴随对象,因此它会在消除HashMap.apply[String, String, ActorRef](...)之类的内容之后结束。

但是这个表达式仍有一个大问题,HashMap只有两个类型参数,一个用于键,一个用于值。看看你的代码似乎所需的键是一个元组。所以要使其有效:HashMap[(String, String), ActorRef](...)

现在为最后一次修复Props[new classobject],再次混淆类型参数。类型参数需要类型而不是实例,任何“新事物”都会创建某个实例。你必须Props[SomeClass]。作为一个快速的方面,术语“类对象”通常不是指类的实例,而是类本身。

第二个样本的句法有效版本:

val activeClasses = HashMap[(String, String), ActorRef](
   ("commonname" ->  "Fqcn", actorOf(Props[SomeClass]))
)

回到第一个样本和这个特定的行:

val actRef = actorSystem.actorOf(Props[clazz])

clazz这里是Class [_]的一个实例,上面甚至不是有效的代码。似乎Props.apply[T <: ActorRef]...需要一个类型,它将负责为您实例化它。但是你只有包含类的Class [_]。怎么解决这个?它发生了另一个Props.apply,而是采用将要实例化的actor类的构造,看看它的签名:

def apply(creator: ⇒ Actor)

为什么不使用这个?

classnames = List[String]("fqcn", "fqcn", "fqcn"....)
for (name <- classnames) {
     val clazz = classLoader.forName(name)
     val actRef = 
        actorSystem.actorOf(Props( clazz.newInstance.asInstanceOf[Actor] )) 
}

假设第二个样本将以某种方式依赖第一个类:

val activeClasses = HashMap[(String, String), ActorRef](
   ("commonname" ->  "Fqcn", 
     actorOf(Props( clazz.newInstance.asInstanceOf[Actor] ) )
)

关于这些样本的一些评论:

  • 两种类型参数都是不必要的。编译器可以为您推断。
  • 您可以使用(a -> b, c),而不是使用a -> b ->来定义第一个元素是元组的元组,而((a,b),c)将导致->。 {{1}}是左关联的。

答案 1 :(得分:2)

由于clazz来自classLoader,因此无法使用Props []创建ActorRef

所以请改用Props.apply

actorOf(Props(clazz.newInstance.asInstanceOf[Actor]))

答案 2 :(得分:2)

在Akka邮件列表中回答:https://groups.google.com/group/akka-user/browse_thread/thread/6823203b3c8470be/8ad21fcfb39b0e25?lnk=gst&q=dynamicAccess

简而言之,创建一个处理动态类加载的Akka扩展并获取传入的ExtendedActorSystem,通过“dynamicAccess”方法获取其DynamicAccess并使用它加载类。这将使用与Akka中所有动态类加载相同的ClassLoader,它与传递给ActorSystem时的ClassLoader相同。