如何在Scala中实例化由type参数表示的类型的实例

sca*_*out 34 generics scala type-parameter

例:

import scala.actors._  
import Actor._  

class BalanceActor[T <: Actor] extends Actor {  
  val workers: Int = 10  

  private lazy val actors = new Array[T](workers)  

  override def start() = {  
    for (i <- 0 to (workers - 1)) {  
      // error below: classtype required but T found  
      actors(i) = new T  
      actors(i).start  
    }  
    super.start()  
  }  
  // error below:  method mailboxSize cannot be accessed in T
  def workerMailboxSizes: List[Int] = (actors map (_.mailboxSize)).toList  
.  
.  
.  
Run Code Online (Sandbox Code Playgroud)

注意第二个错误表明它知道actor项是"T",但不是"T"是actor的子类,而是在类通用定义中受到约束.

如何纠正此代码(使用Scala 2.8)?

oxb*_*kes 25

编辑 - 道歉,我只是注意到你的第一个错误.没有办法T在运行时实例化,因为编译程序时类型信息会丢失(通过类型擦除)

您将不得不通过一些工厂来实现建设:

class BalanceActor[T <: Actor](val fac: () => T) extends Actor {
  val workers: Int = 10

  private lazy val actors = new Array[T](workers)

  override def start() = {
    for (i <- 0 to (workers - 1)) {
      actors(i) = fac() //use the factory method to instantiate a T
      actors(i).start
    }
    super.start()
  }
} 
Run Code Online (Sandbox Code Playgroud)

这可能与某些演员一起使用CalcActor如下:

val ba = new BalanceActor[CalcActor]( { () => new CalcActor } )
ba.start
Run Code Online (Sandbox Code Playgroud)

暂且不说:您可以使用until而不是to:

val size = 10
0 until size //is equivalent to:
0 to (size -1)
Run Code Online (Sandbox Code Playgroud)


Wal*_*ang 15

使用清单:

class Foo[A](a: A)(implicit m: scala.reflect.Manifest[A]) {
  def create: A = m.erasure.newInstance.asInstanceOf[A]
}

class Bar

var bar1 = new Bar       // prints "bar1: Bar = Bar@321ea24" in console
val foo = new Foo[Bar](bar1)
val bar2 = foo.create    // prints "bar2: Bar = Bar@6ef7cbcc" in console
bar2.isInstanceOf[Bar]   // prints "Boolean = true" in console
Run Code Online (Sandbox Code Playgroud)

显然,Manifest在2.7.X中没有记录,所以要小心使用它.相同的代码也在每晚2.8.0中运行.

  • 由于m.erasure现已弃用,您应该使用m.runtimeClass.newInstance().asInstanceOf [D] .get.toString (2认同)

Jos*_*osh 13

现在有一个正确而安全的方法.Scala 2.10引入了TypeTags,它实际上使我们能够在使用泛型类型时克服擦除问题.

现在可以按如下方式对您的类进行参数化:

class BalanceActor[T <: Actor :ClassTag](fac: () => T) extends Actor {
    val actors = Array.fill[T](10)(fac())
}
Run Code Online (Sandbox Code Playgroud)

通过这样做,我们要求在实例化类时可以使用隐式ClassTag [T].编译器将确保这种情况并生成将ClassTag [T]传递给类构造函数的代码.ClassTag [T]将包含有关T的所有类型信息,因此,编译时编译时可用的相同信息(预擦除)现在也可以在运行时使用,使我们能够构建一个数组[T].

请注意,仍然无法做到:

class BalanceActor[T <: Actor :ClassTag] extends Actor {
    val actors = Array.fill[T](10)(new T())
}
Run Code Online (Sandbox Code Playgroud)

这不起作用的原因是编译器无法知道类T是否具有无参数构造函数.

  • @scaling_out这可能是公认的答案 - 自09年以来事情已经开始,我觉得这是16年来人们提出问题的最佳选择. (2认同)