Scala 2.9中的奇怪转换(.asInstanceOf [T])行为

时间:2011-12-18 22:35:54

标签: generics scala types casting parallel-processing

我正在编写一个用于并行计算的软件。该软件是完全通用的,因此我需要一个类来包装序列。

现在,我在地图功能中遇到了奇怪的行为。 map函数将函数对象作为输入,它可以输出与其输入参数不同的类型。

看看以下代码:

class SeqMPJ[T](indexedSeq: IndexedSeq[T]) {

  val seq = indexedSeq.view //Lazy
  val freeRanks = MPJEnv.getFreeRanks(seq.size)
  //Get n free ranks
  val commGroup = MPI.COMM_WORLD.group.Incl(freeRanks.toArray)
  //Communicator for this sequence
  val comm = MPI.COMM_WORLD.Create(commGroup)

  val opIndex = globalRank % seq.size
  var operand: Any = seq(opIndex)

  if (!isOnline)
    error("Cannot use MPJ-abstractions outside parallelize body...")

  //Only works for p=n now
  def mapMPJ[U](f: (T) => U): SeqMPJView[U] = {
    if (freeRanks.contains(globalRank)) { //Process is part of this operation
      operand = f(operand.asInstanceOf[T])
    }
    return new SeqMPJView(operand.asInstanceOf[U], comm, freeRanks)
  }

...

请注意,在函数mapMPJ[U](f: (T) => U):SeqMPJView[U]中,函数f具有输入类型T和输出类型U.这意味着,在将f应用于变量“operand”之后,操作数是U类型,但是,这发生在内部if-block。换句话说,根据状态,操作数可以是U或T.现在,当我转换为U时,它总是成功。即使if块中的条件失败。正如我所看到的,如果程序没有进入if-block,程序在转换operand.asInstanceOf [U]时应该会失败。

示例用法在此矩阵乘法中:

val M = 2
val N = 2

val A = Array(
  Array(1.0, 2.0),
  Array(3.0, 4.0))

val B = Array(
  Array(1.0, 2.0),
  Array(3.0, 4.0))

val Bt = B.transpose

/*
 * DNS using underlying MPI
 */
parallelize(args) {

  for (i <- 0 until M; j <- 0 until N)
    A(i) zip Bt(j) mapMPJ { case (a, b) => a * b } reduceMPJ (_ + _)

  if (globalRank == 0)
    println("CHECK RESULT:\n" + Matrix(A) * Matrix(B))

}

该程序使用最新的eclipse scala IDE进行编译和运行。我没有尝试过其他编译器,但可能是我失明了,但我花了很多时间,所以我希望得到一些帮助:)

修改

从Array到seqMPJ,FYI的隐式转换。

1 个答案:

答案 0 :(得分:4)

当涉及泛型类型参数时,Casting就是你向编译器断言你知道你在做什么以及类型是什么。他们真的只是AnyRef == java.lang.Object(或者无论边界类型是什么)。如果你撒谎,它会相信你(直到由于在某个地方使用了类型错误而导致运行时异常)。如果您想知道自己是否拥有正确的类型,则需要查看清单。

以下是一个例子:

def example[A: ClassManifest,B: ClassManifest](a: A) = {
  if (implicitly[ClassManifest[A]] <:< implicitly[ClassManifest[B]]) a.asInstanceOf[B]
  else throw new Exception("Wrong!")
}

如果你尝试一个不起作用的演员,这会对你大喊:

scala> example[List[Int],List[String]](List())
java.lang.Exception: Wrong!

您可以相应地修改代码,例如

implicitly[ClassManifest[U]].erasure.isAssignableFrom(operand.getClass)