从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中的一些隐式,比如ArrayOps
和WrappedArray
,作为额外的辅助方法。
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)
。