复合类型的元素数组

时间:2014-11-23 01:13:50

标签: scala

我最近一直在使用复合类型,最近我尝试使用以下代码:

import scala.reflect._

object Main {

  def main(args: Array[String]) {
    val a1 = classTag[Int with String with Double].newArray(3)
    println(a1.mkString(" "))

    val a2 = classTag[String with Int with Double].newArray(3)
    println(a2.mkString(" "))

    val a3 = classTag[Double with Int with String].newArray(3)
    println(a3.mkString(" "))
  }

}

使用以下输出:

0 0 0
null null null
0.0 0.0 0.0

这对我来说有点奇怪。每个数组元素都可以访问三种类型的方法:Int,String和Double。这里到底发生了什么?复合类型实际上是第一种类型的实例?复合类型可以显式实例化吗?他们的用例仅适用于组成复合的类型通过继承相关的情况等等?感谢。

P.S。:我使用Scala 2.11.4

1 个答案:

答案 0 :(得分:3)

  

这里的幕后发生了什么?复合类型实际上是第一种类型的实例吗?

查看为newArray定义的ClassTag方法:

override def newArray(len: Int): Array[T] =
   runtimeClass match {
     case java.lang.Byte.TYPE      => new Array[Byte](len).asInstanceOf[Array[T]]
     case java.lang.Integer.TYPE   => new Array[Int](len).asInstanceOf[Array[T]]
     /* snip */
     case _                        => java.lang.reflect.Array.newInstance(runtimeClass, len).asInstanceOf[Array[T]]
   }

然后你的类型:

scala> classTag[Int with String with Double].runtimeClass
res4: Class[_] = int

似乎很清楚它是如何得出使用第一种类型的结论的。 runtimeClass Int with String with DoubleIntnewArray方法使用runtimeClass构建新Array。因此Array填充了默认的Int值。同样适用于其他订单组合。

为什么运行时类Int?好吧,Int with String with Double不是真正的类,但Int是。{1}}。编译器选择使用哪个类只能是任意的,为什么不是第一个呢?

  

复合类型是否可以显式实例化?

我不确定你的意思。如果你考虑一下,编译器必须支持这种组合中的一种类型。明确的Int with String with Double会是什么样的?那么Int with String with Double with Product with Process呢?我也不知道。

  

每个数组元素都可以访问三种类型的方法:Int,String和Double

他们这样做,但他们没有。

scala> val arr = classTag[Int with Process].newArray(3)
arr: Array[Int with Process] = Array(0, 0, 0)

scala> arr(0).exitValue()
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Process

你真的只是欺骗编译器相信你有Array这些类型,而实际上你不是(而且不能,因为没有什么可以是一个子 - IntProcess)的类型。

  

它们的用例仅适用于组成复合的类型通过继承等相关的情况?

差不多,是的。如果您想要尝试直接构建这些类型的任何情况,我无法思考。它们的主要用例是保证类型继承自其他特定类型。

例如,一个方法要求参数从两个特征继承方法:

trait Hello { def hello = println("Hello") }

trait Bye { def bye = println("Bye") }

def greet(hb: Hello with Bye): Unit = { hb.hello; hb.bye }

class A extends Hello

class B extends Hello with Bye

scala> greet(new A)
<console>:15: error: type mismatch;
  found   : A
  required: Hello with Bye
          greet(new A)
                ^

scala> greet(new B)
Hello
Bye