示例:
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
.
.
.
注意第二个错误表明它知道actor项是“T”,但并不是说“T”是actor的子类,而是在类通用定义中受约束。
如何更正此代码(使用Scala 2.8)?
答案 0 :(得分:24)
编辑 - 道歉,我只是注意到你的第一个错误。无法在运行时实例化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()
}
}
这可能与某个演员CalcActor
一起使用,如下所示:
val ba = new BalanceActor[CalcActor]( { () => new CalcActor } )
ba.start
暂且不说:您可以使用until
代替to
:
val size = 10
0 until size //is equivalent to:
0 to (size -1)
答案 1 :(得分: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
BTW,Manifest在2.7.X中没有记录,所以要小心使用它。同样的代码也可以在每晚2.8.0中使用。
答案 2 :(得分:13)
现在这是一种正确而安全的方式。 Scala 2.10引入了TypeTags,它实际上使我们能够在使用泛型类型时克服擦除问题。
现在可以按如下方式对您的课程进行参数设置:
class BalanceActor[T <: Actor :ClassTag](fac: () => T) extends Actor {
val actors = Array.fill[T](10)(fac())
}
通过这样做,我们要求在实例化类时可以使用隐式ClassTag [T]。编译器将确保这种情况并生成将ClassTag [T]传递给类构造函数的代码。 ClassTag [T]将包含有关T的所有类型信息,因此,编译时编译时可用的相同信息(预擦除)现在也可以在运行时使用,使我们能够构建一个数组[T]。
请注意,仍然无法做到:
class BalanceActor[T <: Actor :ClassTag] extends Actor {
val actors = Array.fill[T](10)(new T())
}
这不起作用的原因是编译器无法知道类T是否具有无参数构造函数。
答案 3 :(得分:2)
如上所述,由于擦除,您无法实例化T
。在运行时,没有T
。这不像C ++的模板,其中替换发生在编译时,并且实际编译多个类,用于实际使用中的每个变体。
清单解决方案很有意思,但假设T
有一个不需要参数的构造函数。你不能假设。
至于第二个问题,方法mailboxSize
受到保护,因此您无法在另一个对象上调用它。 更新:这仅适用于Scala 2.8。