【发布时间】:2013-01-14 10:44:00
【问题描述】:
我有许多类的共同基本特征。我有一个函数需要创建这些类之一的实例的新实例,但只有在运行时才知道哪一个。
是否可以将此类作为参数传递并在 Scala 中在运行时创建实例?
我什至不确定答案是否是最好的方法,但目前这是我能想到的唯一方法。
【问题讨论】:
标签: scala
我有许多类的共同基本特征。我有一个函数需要创建这些类之一的实例的新实例,但只有在运行时才知道哪一个。
是否可以将此类作为参数传递并在 Scala 中在运行时创建实例?
我什至不确定答案是否是最好的方法,但目前这是我能想到的唯一方法。
【问题讨论】:
标签: scala
你可以这样传递值:
myFunc(classOf[myObj])
到带有签名的方法
def myFunc(clazz : AnyRef)={ ...
但这闻起来很糟糕。您正在考虑实现factory pattern,或者更好的是您可以使用多态性并简单地执行以下操作:
myObj.myFunc
因为您的功能取决于所涉及的类。
【讨论】:
与 Java 相同:
classOf[MyClass].newInstance // calls the constructor without parameters
classOf[MyClass].getConstructor(/* parameter types */).newInstance(/* parameters */)
这适用于任何 Scala 版本。 Scala 2.10 有new reflection libraries,它们了解 Scala 概念。
【讨论】:
我建议尽量避免反射,因为它很容易导致难以测试的代码和运行时异常。
但是,您可以为该类创建一个构建器,如下所示:
trait Builder[A]{
def newItem:A
}
然后将适当的构建器传递给您的函数
def myFunc[A](param1:B,builder:Builder[A])
你也可以利用隐式
def myFunc[A](param1:B)(implicit builder:Builder[A])
也许您可以详细说明一下您的用例?
【讨论】:
我个人会避免反思。
如果您可以预先识别所有可能的用例并使用标识符对其进行分类:
trait SUPER
class A extends SUPER
class B extends SUPER
class C extends SUPER
class D extends SUPER
val idA = 'CLASS_A
val idB = 'CLASS_B
val idC = 'CLASS_C
val idD = 'CLASS_D
def build(selectedId: Symbol): SUPER = selectedId match {
case 'CLASS_A => new A
case 'CLASS_B => new B
case 'CLASS_C => new C
case 'CLASS_D => new D
}
如果您更喜欢建筑商,我会遵循 @Edmondo1984 的建议
【讨论】:
获得所需内容的最“无缝”方式是将执行实例化的方法声明为具有上下文绑定为 ClassManifest 的类型参数
def maker[T : ClassManifest](args...): T = ...
这将导致编译器自动将ClassManifest[T] 的实例传递给制造商。调用者只需要指定他们想要实例化的特定类。
package rrs.scribble
import scala.reflect.ClassManifest
object Maker
{
def maker[T : ClassManifest]: T = {
val cmT = implicitly[ClassManifest[T]]
val cT = cmT.runtimeClass
cT.newInstance.asInstanceOf[T]
}
}
这只适用于有问题的类的无参数构造函数。您可以使用参数调用构造函数,但涉及更多。您必须熟悉 Java 反射 API。
在 REPL 中:
scala> import rrs.scribble.Maker._
import rrs.scribble.Maker._
scala> class Argless
defined class Argless
scala> val s1 = maker[Argless]
s1: Argless = Argless@1512d075
【讨论】: