Generics Scala 2.9中的奇怪铸造(.asInstanceOf[T])行为

Generics Scala 2.9中的奇怪铸造(.asInstanceOf[T])行为,generics,scala,types,casting,parallel-processing,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

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

现在,我在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块内部。换句话说,根据状态的不同,操作数的类型为U或T。现在,当我强制转换为U时,它总是成功的。即使if块中的条件失败。在我看来,如果程序没有进入if块,则在强制转换操作数.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))

}
val M=2
val N=2
val A=数组(
阵列(1.0,2.0),
阵列(3.0、4.0))
val B=数组(
阵列(1.0,2.0),
阵列(3.0、4.0))
val Bt=B.转置
/*
*使用底层MPI的DNS
*/
并行化(args){

对于(iCasting)来说,当涉及泛型类型参数时,您只需向编译器声明您知道自己在做什么以及类型到底是什么。它们实际上都是
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!")
}
您可以相应地修改代码,例如:

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

强制转换就是你向编译器声明你知道自己在做什么,以及泛型类型参数的类型是什么。它们实际上都是
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!")
}
您可以相应地修改代码,例如:

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

请详细说明这一部分:“隐式[ClassManifest[A]]隐式[ClassManifest[U]]。erasure.isAssignableFrom(Operator.getClass)是类型兼容性的运行时测试:如果可以将操作数分配给U类型的变量,即操作数的运行时类型是U()@Felix-
我接受了答案,因为它解释了我的代码编译的原因。请详细说明这一部分:“隐式[ClassManifest[A]]隐式[ClassManifest[U]]。擦除。isAssignableFrom(operand.getClass)是类型兼容性的运行时测试:如果可以将操作数赋给U类型的变量,即如果操作数的运行时类型是U()的子类型,则返回true@Felix-
我接受了这个答案,因为它解释了我的代码编译的原因。你欺骗类型检查器的方式令人不安,可能没有必要。你考虑过使用[A,B]作为操作数的类型?注释提示您可能不需要处于另一种状态的操作数。如果不采用if,是否希望稍后将函数应用于操作数?在这种情况下,我将使用:
trait Result[U]{def res:U}case class Computed[U](res:U)扩展结果[U]case class到compute[T,U](T:T,f:T=>U)扩展结果[U]{def get=f(t)}
我将使您现在所称的操作数具有type
Result[U]
(并重命名它)。在if子句失败的情况下,我不需要操作数。但是,我必须返回一个新的SeqMPJView!或者[a,B]?是否为关键字?
or
是标准的Scala数据类型;在定义
SeqMPJView
时,可能应该使用
选项
,以指定不需要向其传递值。
or[a,B]
允许提供类型
a
或类型
B
的值,如类型安全联合。您欺骗类型检查器的方式令人不安,可能没有必要。您是否考虑过使用[a,B]作为操作数的类型?注释提示您可能不需要处于另一种状态的操作数。如果不采用if,是否希望稍后将函数应用于操作数?在这种情况下,我将使用:
trait Result[U]{def res:U}case class Computed[U](res:U)扩展结果[U]case class到compute[T,U](T:T,f:T=>U)扩展结果[U]{def get=f(t)}
我将使您现在所称的操作数具有type
Result[U]
(并重命名它)。在if子句失败的情况下,我不需要操作数。但是,我必须返回一个新的SeqMPJView!或者[a,B]?或者是关键字?
或者
是标准的Scala数据类型;在定义
SeqMPJView
时,可能应该使用
选项
,以指定不需要向其传递值。
或者[a,B]
允许提供类型
a
或者类型
B
的值,就像类型安全的联合。