有效地将 AnyVal case class (Seq[T <: AnyVal]) 的序列转换为其运行时表示
Convert sequence of AnyVal case class (Seq[T <: AnyVal]) to its runtime representation efficiently
假设我有一个值案例 class
case class Id(i:Int) extends AnyVal
和包含此值的序列 case class
Seq(Id(1), Id(2), Id(3))
有没有一种方法可以将这些值转换为 Int
而无需对序列进行迭代(例如通过执行 Seq(Id(1), Id(2), Id(3)).map(_.i)
?
我问的原因是我认为值案例 classes 的好处是你可以在运行时使用具有本机类型的值 classes 作为表示,因此非常高效的。但并非所有使用中的库都支持那些 class 中的自动 "conversions"。因此,当它是一个简单的属性时,必须传递本机类型没什么大不了的,因为编译器可以优化它。但是当有一个序列时,我必须明确地映射它,这意味着对所有值都会发生不必要的迭代,因为它实际上除了在运行时映射到相同的值外什么都不做。在这种情况下,有什么办法可以避免这种情况并使用编译器的一些优化吗?
正如 Alexey Romanov 在评论中推测的那样,值 类 在存储在 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
注意 return 类型是 Seq<Id>
并且 Id."<init>"
在第 17 行被调用。鉴于此,没有映射的拆箱是不可能的。
如果该提案被接受,此装箱的解决方案将在 Scala 3 中 Opaque Types。不过,我不确定他们是否能解决您的问题。
假设我有一个值案例 class
case class Id(i:Int) extends AnyVal
和包含此值的序列 case class
Seq(Id(1), Id(2), Id(3))
有没有一种方法可以将这些值转换为 Int
而无需对序列进行迭代(例如通过执行 Seq(Id(1), Id(2), Id(3)).map(_.i)
?
我问的原因是我认为值案例 classes 的好处是你可以在运行时使用具有本机类型的值 classes 作为表示,因此非常高效的。但并非所有使用中的库都支持那些 class 中的自动 "conversions"。因此,当它是一个简单的属性时,必须传递本机类型没什么大不了的,因为编译器可以优化它。但是当有一个序列时,我必须明确地映射它,这意味着对所有值都会发生不必要的迭代,因为它实际上除了在运行时映射到相同的值外什么都不做。在这种情况下,有什么办法可以避免这种情况并使用编译器的一些优化吗?
正如 Alexey Romanov 在评论中推测的那样,值 类 在存储在 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
注意 return 类型是 Seq<Id>
并且 Id."<init>"
在第 17 行被调用。鉴于此,没有映射的拆箱是不可能的。
如果该提案被接受,此装箱的解决方案将在 Scala 3 中 Opaque Types。不过,我不确定他们是否能解决您的问题。