将AnyVal案例类(Seq [T <:AnyVal])的序列有效地转换为其运行时表示

Big*_*989 6 scala seq value-class

假设我有一个值案例类

case class Id(i:Int) extends AnyVal
Run Code Online (Sandbox Code Playgroud)

以及包含此值case类的序列

Seq(Id(1), Id(2), Id(3))
Run Code Online (Sandbox Code Playgroud)

是否有一种方法可以将这些值转换Int为不需要迭代序列(例如通过执行Seq(Id(1), Id(2), Id(3)).map(_.i)

我问的原因是我认为值case case类的优点在于你可以使用在运行时具有本机类型作为表示的值类,因此非常有效.但并非所有使用的库都支持这些类的自动"转换".因此,当它是一个简单的属性时,必须传递本机类型,因为编译器可以优化它.但是当有一个序列时我必须显式地映射它,这意味着在所有值上发生了不必要的迭代,因为它实际上什么也没做,只是在运行时映射到相同的值.有没有办法避免这种情况,并在这种情况下使用编译器的一些优化?

Bri*_*hon 2

正如 Alexey Romanov 在评论中推测的那样,值类在存储在Seq. javap -c这是for的输出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
Run Code Online (Sandbox Code Playgroud)

请注意,返回类型是Seq<Id>and thatId."<init>"在第 17 行调用。考虑到这一点,在没有映射的情况下拆箱是不可能的。

如果该提案被接受,此拳击的解决方案将是Scala 3 中的不透明类型。不过,我不确定他们是否能解决您的问题。