可変長引数定義したり渡したりしたときの実装がどうなっているかのメモ
以下のコード↓
object Test{ def hoge(a:Any*) = a.toList val b = hoge( 1 , "xyz",'abc ) }
を、逆コンパイルすると↓
import scala.*; import scala.collection.Seq; import scala.collection.TraversableOnce; import scala.collection.immutable.List; import scala.runtime.BoxesRunTime; public final class Test$ implements ScalaObject { public List hoge(Seq a) { return a.toList(); } public List b() { return b; } private Test$() { b = hoge(Predef$.MODULE$.genericWrapArray(((Object) (new Object[] { BoxesRunTime.boxToInteger(1), "xyz", symbol$1 })))); } public static final Test$ MODULE$ = this; private final List b; private static final Symbol symbol$1; static { symbol$1 = (Symbol)Symbol$.MODULE$.apply("abc"); new Test$(); } }
となった。可変長を受け取る側はSeqになるのは知ってたけど、渡す側はgenericWrapArrayっていうのになっていて、名前からしても、それに渡しているのが配列ってところからも、ちょっと配列をwrapしてるだけのものっぽいことが予想できる。
で、Predefの中grepしてもgenericWrapArrayなんてない(´・ω・`)
なので、ソース全体grepすると、scala.LowPriorityImplicits.scala(コード、scaladoc)の中にあった。
で、結局そのなかで、
implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): WrappedArray[T] = if (xs ne null) new WrappedArray.ofRef[T](xs) else null
っていうことやってる。
そして、じゃあ、WrappedArrayってどういうclassかっていうと、これ
やっぱり配列の薄いラッパーだった。WrappedArrayはSeqを継承してるから、可変長の引数として渡せる。
あと、渡しているものが、プリミティブ型の配列に出来る場合はそれ用に最適化してるみたいですね
ちなみに、2.8.1で調べましたが、言語仕様で決まってるのかどうかは知らないので、versionによって変わるかも