Эффективно преобразовать последовательность класса случаев AnyVal (Seq [T <: AnyVal]) в его представление во время выполнения - PullRequest
0 голосов
/ 14 января 2019

Предположим, у меня есть класс значений

case class Id(i:Int) extends AnyVal

и последовательность, содержащая этот регистр значений

Seq(Id(1), Id(2), Id(3))

есть ли способ конвертировать эти значения в Int, без необходимости в итерации по последовательности (например, с помощью Seq(Id(1), Id(2), Id(3)).map(_.i)?

Причина, по которой я спрашиваю, состоит в том, что я думаю, что хорошая вещь в классах значений - это то, что вы можете использовать классы значений, которые имеют нативные типы в качестве представления во время выполнения и, следовательно, чрезвычайно эффективны. Но не все используемые библиотеки поддерживают автоматическое «преобразование» этих классов. Таким образом, нужно передать нативный тип, что не составляет большого труда, когда он является простым атрибутом, поскольку компилятор может его оптимизировать. Но когда у меня есть последовательность, я должен явно отобразить ее, что означает, что происходит ненужная итерация по всем значениям, потому что она на самом деле ничего не делает, кроме отображения на одни и те же значения во время выполнения. Есть ли способ избежать этого и использовать некоторые оптимизации компилятора в таких случаях?

1 Ответ

0 голосов
/ 15 января 2019

Как предположил Алексей Романов в комментариях, классы значений на самом деле отображаются при сохранении в Seq. Вот вывод javap -c для def bar = Seq(Id(1)):

  public scala.collection.Seq<Id> bar();
    Code:
       0: getstatic     #25                 // Field scala/collection/Seq$.MODULE$:Lscala/collection/Seq$;
       3: getstatic     #30                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
       6: iconst_1
       7: anewarray     #32                 // class Id
      10: dup
      11: iconst_0
      12: new           #32                 // class Id
      15: dup
      16: iconst_1
      17: invokespecial #35                 // Method Id."<init>":(I)V
      20: aastore
      21: invokevirtual #39                 // Method scala/Predef$.genericWrapArray:(Ljava/lang/Object;)Lscala/collection/mutable/WrappedArray;
      24: invokevirtual #43                 // Method scala/collection/Seq$.apply:(Lscala/collection/Seq;)Lscala/collection/GenTraversable;
      27: checkcast     #45                 // class scala/collection/Seq
      30: areturn

Обратите внимание, что тип возвращаемого значения Seq<Id> и что Id."<init>" вызывается в строке 17. При этом распаковка без сопоставления невозможна.

Решением для этого бокса будет Непрозрачные типы в Scala 3, если это предложение будет принято. Но я не уверен, что они решат вашу проблему.

...