Runtime resolution of type arguments using scala 2.10 reflection

有些话、适合烂在心里 提交于 2019-12-30 06:23:52

问题


Given a type declaration, I am able to resolve the type argument.

scala> reflect.runtime.universe.typeOf[List[Int]] match {case x:TypeRef => x.args}
res10: List[reflect.runtime.universe.Type] = List(Int)

For a runtime value, The same method doesn't work.

scala> reflect.runtime.currentMirror.reflect(List(42)).symbol.toType match {case x:TypeRef => x.args}
res11: List[reflect.runtime.universe.Type] = List(B)

Is there a way to overcome the type erasure for reflected values?


回答1:


An example based on TypeTag knowledge gained from reading Scala: What is a TypeTag and how do I use it? posted by Eugene Burmako in the comments on your question:

import scala.reflect.runtime.universe._

object ScalaApplication {
  def main(args: Array[String]) {
    printType(List(42))
    printType(List("42"))
    printType(List("42", 42))
  }    

  def printType[T : TypeTag](t: T) {
    println(typeOf[T])
  }
}

This should give the output:

$ scala ScalaApplication.scala 
List[Int]
List[String]
List[Any]

[UPDATE 1:]

However, if you want to be aware of the type assigned to a reference of type Any you might have to opt for some sort of type aware wrapper:

import scala.reflect.runtime.universe._

object ScalaApplication {
  def main(args: Array[String]) {
    val anyWrapper = new AnyWrapper

    List(1,2,3).foreach { i =>
      i match {
        case 1 => anyWrapper.any = 42
        case 2 => anyWrapper.any = "a string"
        case 3 => anyWrapper.any = true
      }
      print(anyWrapper.any)
      print(" has type ")
      println(anyWrapper.typeOfAny)
    }
  }

  class AnyWrapper {
    private var _any: Any = null
    private var _typeOfAny: Type = null

    def any = _any
    def typeOfAny = _typeOfAny
    def any_=[T: TypeTag](a: T) = {
      _typeOfAny = typeOf[T]
      _any = a
    }

  }
}

This should give the output:

$ scala ScalaApplication.scala 
42 has type Int
a string has type String
true has type Boolean

But this solution still does not cover the case where the reference type is unknown at compile time.

[UPDATE 2:]

If the types are explicitly cast to reference of type Any, you might have to enumerate all the possible types in a match statement in order to recover the type:

import scala.reflect.runtime.universe._

object ScalaApplication {
  def main(args: Array[String]) {

    List(1,2,3).foreach { i =>
      val any: Any = i match {
        case 1 => 42.asInstanceOf[Any]
        case 2 => "a string".asInstanceOf[Any]
        case 3 => true.asInstanceOf[Any]
      }
      print(any)
      print(" has type ")
      println(matchType(any))
    }
  }

  def matchType(any: Any) = {
    any match {
      case a: Int => typeOf[Int]
      case a: String => typeOf[String]
      case a: Boolean => typeOf[Boolean]
    }
  }
}

This should give the output:

$ scala ScalaApplication.scala
42 has type Int
a string has type String
true has type Boolean

But this solution requires you to know (and list) all the possible types that you could receive in the any value.



来源:https://stackoverflow.com/questions/12458502/runtime-resolution-of-type-arguments-using-scala-2-10-reflection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!