我不确定你是否想要一个使用宏的解决方案,但为了记录(因为我之前已经准确地编写过这个方法),这里是你如何在 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
所有都按预期静态键入,如果你给它一个超出范围的索引(或不是文字),你会得到一个很好的编译时错误。