2015-06-23 3 views
1

С array.scala из-2.10.4 лестницу, The Массив определяется какчто магия Скала Array.apply

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

Обратите внимание, что метод применяется сгенерирует исключение! А для сопровождения объекта 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()); 
    ... 
} 

Я действительно смущен этим видом перевода, что такое правило под капотом?

Благодаря Чанг

+0

['ClassTag [T]'] (http://www.scala-lang.org/files/archive/nightly/docs/library/index.html#scala.reflect.ClassTag) имеет метод 'newArray' который создает новый 'Array [T]' –

+0

@PeterNeyens, я знаю, что существует метод newArray, но я не знаю, почему newArray выбран путем компиляции – Chang

+0

Цитируя первую строку [Manifest [T] '] (http : //www.scala-lang.org/files/archive/nightly/docs/library/index.html#scala.reflect.Manifest) (подкласс класса ClassTag [T] '):" _Its поддерживается использование, чтобы дать доступ к стиранию типа как экземпляра класса, как это необходимо для создания собственных массивов, если класс неизвестен во время компиляции. « –

ответ

1

на JVM массивы освобождаются от типа стирания, например во время выполнения вместо Array[_] существует разница между Array[Int], Array[String] и Array[AnyRef], например. В отличие от Java, Scala может справиться с этим преимущественно прозрачным, так что

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

имеет прямой байт-кода вызова для создания целых чисел, тогда как

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

решается с помощью неявного параметра типа доказательств типа ClassTag[A], так что во время выполнения JVM может создать правильный массив. Это переведено на звонок, который вы видели, ev.newArray(123).

+0

Насколько мне известно, для ссылки на такой параметр доказательства нам нужно что-то вроде этого: val tag = неявно [ClassTag [T]]; tag.newArray (123). Однако в этой ситуации новый Array [T] непосредственно переводится в ev.newArray (123). Я не могу поверить, что scala-компиляция делает какую-то магическую вещь, когда они встречают новый Array [T] – Chang

+1

Другими словами, ответ на вопрос в заголовке «Что такое магия Scala' Array.apply» - это «это действительно» * магия ". –

2

Scala Array Класс - это всего лишь фальшивая оболочка для среды выполнения, поэтому вы можете использовать массивы в Scala. Вероятно, вы сбиты с толку, потому что те методы класса Array исключают. Причина, по которой они это сделали, заключается в том, что если вы действительно используете поддельный класс, он взрывается, так как на самом деле он должен использовать массив времени java, который не имеет соответствующего класса контейнера, такого как Scala. Вы можете видеть, как compiler handles it here. Когда вы используете массивы в Scala, вы, вероятно, также используете некоторые импликации из predef, такие как ArrayOps и WrappedArray для дополнительных вспомогательных методов.

TLDR: Scala компилятор магии делает массивы работы с java runtime под капотом.

Смежные вопросы