13

したがって、次のような Scala クラスがあります。

class TestClass {
  var value: Option[Int] = None
}

そして、私は文字列値を持っていて、リフレクションを使用して実行時にその Option[Int] に強制したいという問題に取り組んでいます。したがって、別のコード (TestClass について何も知らない) には、次のようなコードがあります。

def setField[A <: Object](target: A, fieldName: String, value: String) {
  val field = target.getClass.getDeclaredField(fieldName)
  val coercedValue = ???; // How do I figure out that this needs to be Option[Int] ? 
  field.set(target, coercedValue)   
}

これを行うには、フィールドが Option であり、Option の型パラメーターが Int であることを知る必要があります。

「値」のタイプが実行時に Option[Int] であることを理解するためのオプションは何ですか (つまり、リフレクションを使用します)?

@OptionType(Int.class) など、フィールドに注釈を付けることで同様の問題が解決されるのを見てきました。可能であれば、リフレクション ターゲットに注釈を必要としないソリューションを希望します。

4

4 に答える 4

5

Java 1.5 リフレクション API を使用するのは非常に簡単です。

 def isIntOption(clasz: Class[_], propertyName: String) = {
   var result = 
     for {
       method <- cls.getMethods
       if method.getName==propertyName+"_$eq"
       param <- method.getGenericParameterTypes.toList.asInstanceOf[List[ParameterizedType]]
     } yield
       param.getActualTypeArguments.toList == List(classOf[Integer]) 
       && param.getRawType == classOf[Option[_]]
   if (result.length != 1)
     throw new Exception();
   else
     result(0)
 }
于 2010-04-19T20:06:48.993 に答える
3

バイトコードレベルでは、Javaにはジェネリックスがありません。ジェネリックスはポリモーフィズムで実装されているため、ソースコード(この場合はScala)がコンパイルされると、ジェネリック型は消えます(これは型消去と呼ばれます)。これにより、リフレクションを介して汎用ランタイムタイプ情報を収集することはできません。

考えられる(少し汚いですが)回避策は、Genericパラメーターと同じ型であることがわかっているプロパティの実行時型を取得することです。オプションインスタンスの場合、getメンバーを使用できます

object Test {

  def main(args : Array[String]) : Unit = {
    var option: Option[_]= None
    println(getType(option).getName)
    option = Some(1)
    println(getType(option).getName)

  }

  def getType[_](option:Option[_]):Class[_]= {
         if (option.isEmpty) classOf[Nothing] else (option.get.asInstanceOf[AnyRef]).getClass
  }
}
于 2010-04-19T10:51:43.667 に答える
2
class TestClass {
  var value: Option[Int] = None
// ...

  def doSomething {
    value match {
      case Some(i) => // i is an Int here
      case None =>
      // No other possibilities
    }
  }
}
于 2010-04-19T00:17:27.163 に答える
1

問題は、JVM が型消去によってジェネリックを実装することです。そのため、リフレクションを通じて の型がvalueisOption[Int]であることを発見することは不可能です。実行時に実際にはそうではないためOptionです。

2.8 では、次のように使用できるはずですManifests

var value: Option[Int] = None
val valueManifest = implicitly[scala.reflect.Manifest[Option[Int]]]
valueManifest.typeArguments // returns Some(List(Int))
于 2010-04-19T10:29:38.583 に答える