6

我有许多类的共同基本特征。我有一个函数需要创建这些类之一的实例的新实例,但只有在运行时才知道哪一个。

是否可以将此类作为参数传递并在运行时在 Scala 中创建实例?

我什至不确定答案是否是最好的方法,但目前这是我唯一能想到的。

4

5 回答 5

4

您可以这样传递值:

myFunc(classOf[myObj])

到带有签名的方法

def myFunc(clazz : AnyRef)={ ...

但这闻起来很糟糕。您正在考虑实现工厂模式,或者更好的是您可以使用多态性并简单地执行以下操作:

myObj.myFunc

因为您的功能取决于所涉及的类。

于 2013-01-14T10:47:38.573 回答
2

与 Java 相同:

classOf[MyClass].newInstance // calls the constructor without parameters
classOf[MyClass].getConstructor(/* parameter types */).newInstance(/* parameters */)

有关 Class ,请参阅Javadoc

这适用于任何 Scala 版本。Scala 2.10 有新的反射库,它们了解 Scala 概念。

于 2013-01-14T11:05:01.600 回答
1

我建议尽量避免反射,因为它很容易导致难以测试的代码和运行时异常。

但是,您可以为该类创建一个构建器,如下所示:

trait Builder[A]{
   def newItem:A
}

然后将适当的构建器传递给您的函数

def myFunc[A](param1:B,builder:Builder[A])

你也可以利用隐式

def myFunc[A](param1:B)(implicit builder:Builder[A])

也许您可以详细说明您的用例?

于 2013-01-14T11:37:04.167 回答
0

获得所需内容的最“无缝”方式是将执行实例化的方法声明为具有上下文绑定的类型参数ClassManifest

def maker[T : ClassManifest](args...): T = ...

这将导致编译器自动将一个实例传递ClassManifest[T]给 maker。调用者只需要指定他们想要实例化的特定类。

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
于 2013-01-14T15:09:43.907 回答
0

我个人会避免反思。

如果您可以事先识别所有可能的用例并使用标识符对其进行分类:

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 的建议

于 2013-01-14T13:43:36.563 回答