Почему массив классов значений компилируется в массив объектов? - PullRequest
3 голосов
/ 21 января 2020

Как я понимаю, если вы создаете массив класса значений, вы фактически создаете массив объектов, а не обернутый примитив. В чем причина этого?

source:

class Wrapper(val underlying: Int) extends AnyVal

class Main {
  val i: Int = 1
  val w: Wrapper = new Wrapper(1)
  val wrappers = Array[Wrapper](new Wrapper(1), new Wrapper(2))
  val ints = Array[Int](1, 2)
}

javap output:

public class Main {
  public int i();
  public int w();
  public Wrapper[] wrappers(); // <----why can't this be int[] as well
  public int[] ints();
  public Main();
}

Ответы [ 2 ]

6 голосов
/ 21 января 2020

Одним из ограничений классов значений является то, что x.isInstanceOf[ValueClass] все еще должен работать правильно. Где правильно означает: прозрачно, без необходимости знать программисту, когда значения могут быть или не быть помещены в квадрат.

Если Array[Meter] будет представлен как Array[Int] во время выполнения, следующий код не будет работать как ожидается, потому что информация о том, что значения в массиве на самом деле являются метрами, теряется.

class Meter(val value: Int) extends AnyVal

def centimeters[A](as: Array[A]) = as.collect{ case m: Meter => m.value * 100 }

Обратите внимание, что если у вас есть val m = new Meter(42); m.isInstanceOf[Meter], то компилятор знает, что m - это Meter, даже если он Int во время выполнения, и он может встроить isInstanceOf вызов true.

Также обратите внимание, что это не будет работать для массивов. Если бы вы поместили значения в массив по требованию, вам нужно было бы создать новый массив, который не был бы прозрачен для программиста, потому что массивы изменчивы и используют равенство ссылок. Это также было бы катастрофой для производительности с большими массивами.

3 голосов
/ 21 января 2020

Согласно https://docs.scala-lang.org/overviews/core/value-classes.html:

Сводка распределения

Класс значений фактически создается, когда:

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

[...]

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

val m = Meter(5.0)
val array = Array[Meter](m)

Массив содержит фактические экземпляры Meter, а не только базовые двойные примитивы.

Возможно, это как-то связано с типом или просто потому, что вы создаете массив определенного типа c, который не позволяет обрабатывать один тип как другой. В любом случае, это техническое ограничение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...