6

私は、任意のサイズと型のタプルをインデックスとともに受け取り、そのインデックスのタプルの要素を返す Scala メソッドを書きたいと考えています。私はすべてを行う方法を知っていますが、型を保持します。戻り値をタプル項目の動的タイプにする方法はまだわかりません。

これが私がこれまで持っている機能です:

def subscript_get(tup: Product, index:Int): Any={
    return tup.productElement(index)    
}

たとえば、使用法は次のようになります。

subscript_get((0,1,2,3),0) --> Int = 0

subscript_get((0,1,"asdf",3),2) --> java.lang.String = asdf

後で結果を探しているものにキャストできることはわかっていますが、どのタイプにキャストする必要があるかを常に知ることができるとは限らないため、これはうまくいきません。

このようなことは可能ですか?ありがとう!

4

2 に答える 2

11

マクロを使用したソリューションが必要かどうかはわかりませんが、念のため (以前にこのメソッドを正確に記述したことがあるため)、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

すべてが期待どおりに静的に型付けされ、範囲外の (またはリテラルではない) インデックスを指定すると、適切なコンパイル時エラーが発生します。

于 2013-04-30T23:55:01.613 に答える
0

それをしてはいけない。を使用するProductと、タプルの値の (コンパイル時の) 型が失われます。さらに、メソッドは、渡された値に基づいて戻り値の型を適応させることはできません (完全に当てはまるわけではありません。依存メソッドの型を参照してください。ただし、 の場合は当てはまりますInt)。

キャストする型がわからない場合は、パターン マッチングを使用できます。

subscript_get(..., 1) match {
  case v: Int    => // do something with Int
  case v: String => // do something with String
  // snip
  case _ => sys.error("don't know how to handle this")
}
于 2013-04-30T23:00:58.600 に答える