マクロを使用したソリューションが必要かどうかはわかりませんが、念のため (以前にこのメソッドを正確に記述したことがあるため)、2.10 のマクロ システムでこれを実装する方法を次に示します。
上記のコメントで述べたように、このアプローチはindex
整数リテラルである必要があり、2.10 の「指定されていないが意図された」動作に依存しています。また、ドキュメンテーションに関するいくつかのトリッキーな質問も提起されます。
import scala.language.experimental.macros
import scala.reflect.macros.Context
object ProductIndexer {
def at[T <: Product](t: T)(index: Int) = macro at_impl[T]
def at_impl[T <: Product: c.WeakTypeTag](c: Context)
(t: c.Expr[T])(index: c.Expr[Int]) = {
import c.universe._
index.tree match {
case Literal(Constant(n: Int)) if
n >= 0 &&
weakTypeOf[T].members.exists {
case m: MethodSymbol => m.name.decoded == "_" + (n + 1).toString
case _ => false
} => c.Expr[Any](Select(t.tree, newTermName("_" + (n + 1).toString)))
case Literal(Constant(_: Int)) => c.abort(
c.enclosingPosition,
"There is no element at the specified index!"
)
case _ => c.abort(
c.enclosingPosition,
"You must provide an integer literal!"
)
}
}
}
その後:
scala> import ProductIndexer._
import ProductIndexer._
scala> val triple = (1, 'a, "a")
triple: (Int, Symbol, String) = (1,'a,a)
scala> at(triple)(0)
res0: Int = 1
scala> at(triple)(1)
res1: Symbol = 'a
scala> at(triple)(2)
res2: String = a
すべてが期待どおりに静的に型付けされ、範囲外の (またはリテラルではない) インデックスを指定すると、適切なコンパイル時エラーが発生します。