例:
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
.
.
.
2番目のエラーは、アクターアイテムが「T」であることを認識しているが、クラスの一般的な定義で制約されているように、「T」がアクターのサブクラスであることを示していないことに注意してください。
このコードを修正して機能させるにはどうすればよいですか(Scala 2.8)を使用)?
[〜#〜] edit [〜#〜]-お詫びします。最初のエラーに気づいただけです。プログラムのコンパイル時に型情報が失われるため、実行時に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)
マニフェストを使用する:
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
ところで、マニフェストは2.7.Xで文書化されていないため、注意して使用してください。同じコードが2.8.0で毎晩機能します。
これを行うための適切で安全な方法があります。 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に関するすべての型情報が含まれます。その結果、コンパイル時にコンパイラーが利用できるのと同じ情報(事前消去)が実行時にも利用できるようになり、構築が可能になります。 Array [T]。
それでも実行できないことに注意してください。
class BalanceActor[T <: Actor :ClassTag] extends Actor {
val actors = Array.fill[T](10)(new T())
}
これが機能しない理由は、クラスTに引数なしのコンストラクターがあるかどうかをコンパイラーが知る方法がないためです。
すでに述べたように、消去のためにT
をインスタンス化することはできません。実行時には、T
はありません。これは、置換がコンパイル時に行われ、実際の使用のバリエーションごとに複数のクラスが実際にコンパイルされるC++のテンプレートとは異なります。
マニフェストソリューションは興味深いものですが、パラメーターを必要としないT
のコンストラクターがあることを前提としています。あなたはそれを仮定することはできません。
2番目の問題については、メソッドmailboxSize
が保護されているため、別のオブジェクトで呼び出すことはできません。 更新:これはScala 2.8の場合にのみ当てはまります。