Scala Array.apply的魔力何在



从scala-2-10.4的array.scale,数组被定义为

final class Array[T](_length: Int) extends java.io.Serializable with java.lang.Cloneable {    
  /** The length of the array */
  def length: Int = throw new Error()
  def apply(i: Int): T = throw new Error()
  def update(i: Int, x: T) { throw new Error() }
  override def clone(): Array[T] = throw new Error()
}

请注意,apply方法将抛出异常!对于伴随的对象Arrry,我发现以下代码:

  def apply[T: ClassTag](xs: T*): Array[T] = {
    val array = new Array[T](xs.length)
    var i = 0
    for (x <- xs.iterator) { array(i) = x; i += 1 }
    array
  }

我知道有一个隐含的参数是ClassTag[T],让我惊讶的是

新阵列[T](xs.length)

已编译。通过反编译Array.class,我发现这行被翻译成:

public <T> Object apply(Seq<T> xs, ClassTag<T> evidence$2)
{
    // evidence$2 is implicit parameter
    Object array = evidence$2.newArray(xs.length());
    ...  
}

我真的被这种翻译弄糊涂了,这里面的规则是什么?

谢谢Chang

Scala Array类只是一个运行时的假包装器,因此您可以在Scala中使用数组。您可能会感到困惑,因为Array类上的那些方法抛出异常。他们这样做的原因是,如果你真的使用了假类,它就会爆炸,因为实际上它应该使用java运行时数组,而这个数组没有像Scala这样的合适的容器类。您可以在这里看到编译器是如何处理它的。当你在Scala中使用数组时,你可能也在使用predef中的一些隐式,比如ArrayOpsWrappedArray,作为额外的辅助方法。

TLDR:Scala编译器的魔力使数组能够在后台与java运行时一起工作。

在JVM上,数组不受类型擦除的影响,例如,在运行时,Array[Int]Array[String]Array[AnyRef]之间存在差异,而不是Array[_]。与Java不同,Scala可以透明地处理这一问题,因此

class Foo {
  val foo = new Array[Int](123)
}

具有用于创建整数数组的直接字节代码调用,而

class Bar[A](implicit ev: reflect.ClassTag[A]) {
  val bar = new Array[A](123)
}

通过使用类型为CCD_ 9的隐式类型证据参数来解决,以便JVM在运行时仍然可以创建正确的数组。这被翻译成您看到的呼叫ev.newArray(123)

相关内容

  • 没有找到相关文章

最新更新