简体   繁体   English

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

[英]Strange casting (.asInstanceOf[T]) behaviour in Scala 2.9

I am writing a piece of software for parallel computations. 我正在编写用于并行计算的软件。 The software is totally generic, and thus I need a class to wrap sequences. 该软件是完全通用的,因此我需要一个类来包装序列。

Right now, I am experiencing strange behaviour in my map-function. 现在,我在地图功能中遇到了奇怪的行为。 A map function takes a function-object as input, which can output a different type than its input argument. 映射函数将函数对象作为输入,可以输出与其输入参数不同的类型。

Take a look at the following code: 看下面的代码:

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)
  }

... ...

Notice that in the function mapMPJ[U](f: (T) => U):SeqMPJView[U] , the function f has input type T and output type U. This means, after applying f to the variable "operand", operand is of type U, however, this happens inside the if-block. 请注意,在函数mapMPJ[U](f: (T) => U):SeqMPJView[U] ,函数f具有输入类型T和输出类型U。这意味着在将f应用于变量“ operand”之后,操作数的类型为U,但是,这发生在if块内部。 In other words, depending on the state, operand has either type U or T. Now, when I cast to U, it always succeeds. 换句话说,根据状态的不同,操作数的类型为U或T。现在,当我强制转换为U时,操作数始终会成功。 Even when the condition in the if-block fails. 即使if块中的条件失败。 As I see it, the program should fail when casting operand.asInstanceOf[U] if the program does not enter the if-block. 如我所见,如果程序未输入if块,则该程序应在转换Operand.asInstanceOf [U]时失败。

An example usage is in this matrix multiplication: 矩阵乘法的用法如下:

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))

}

The program compiles and runs perfectly using the newest eclipse scala IDE. 该程序可以使用最新的eclipse scala IDE编译并完美运行。 I haven't tried other compilers, but it's probably me being blind, but I spent so much time, so I hope for some help :) 我没有尝试过其他编译器,但是可能是我失明了,但是我花了很多时间,所以希望能有所帮助:)

edit 编辑

There's an implicit conversion from Array to seqMPJ, FYI. 从Array到seqMPJ,FYI有隐式转换。

Casting is just you asserting to the compiler that you know what you are doing and what the type really is, when it comes to generic type arguments. 当涉及泛型类型参数时,强制转换只是向编译器断言您知道自己在做什么以及类型实际上是什么。 They're all really just AnyRef == java.lang.Object (or whatever the bounding type is). 它们实际上只是AnyRef == java.lang.Object (或任何边界类型)。 If you lie to it, it will believe you (until there is a runtime exception caused by having the wrong type somewhere that the type is used). 如果您撒谎,它将相信您(直到在使用该类型的位置出现错误的类型而导致运行时异常)。 If you want to know whether you've got the correct type, you have to check with manifests. 如果您想知道类型是否正确,则必须检查清单。

Here's an example: 这是一个例子:

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

If you try a cast that won't work, this will yell at you: 如果您尝试的转换无效,这将对您大喊:

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

You can modify your code accordingly, eg 您可以相应地修改代码,例如

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM