【问题标题】:How to filter methods by return type with scala reflection?如何使用 scala 反射按返回类型过滤方法?
【发布时间】:2015-01-16 00:28:49
【问题描述】:

我正在尝试测试方法的返回类型是否与提供的类型完全匹配。

不知何故,我发现了两个不相等的字符串类型。

class VarAndValue {
  @BeanProperty
  val value = "";    
}

class ScalaReflectionTest {

  @Test
  def myTest(): Unit = {

    val type1 = universe.typeOf[String]

    // Get return value of VarAndValue.getValue
    val type2 = universe.typeOf[VarAndValue].
      declarations.
      filter { m => m.name.decoded == "getValue" && m.isMethod }.
      head.
      asInstanceOf[universe.MethodSymbol].
      returnType

      println(type1)   // String
      println(type2)   // String
      println(type1.getClass())
      println(type2.getClass()) // !=type1.getClass()   !!
      println(type1==type2)     // False
   }
}

产量...

String
String
class scala.reflect.internal.Types$TypeRef$$anon$3
class scala.reflect.internal.Types$TypeRef$$anon$6
false

如何通过返回类型过滤类的方法? (如果我可以测试返回类型的相等性似乎非常困难)。

Scala 2.10

更新:

我不能进入 Java 反射世界,因为这会删除像 List[Int] 这样的泛型的类型信息(变成 List[Object] 是 Java 领域,它们实际上是 List[java.lang.Integer]) .我需要我的匹配来注意 scala 类型 Universe 保留的通用参数信息。

【问题讨论】:

标签: scala scala-2.10 scala-reflect


【解决方案1】:

使用=:= 比较类型。

scala> import beans._
import beans._

scala> :pa
// Entering paste mode (ctrl-D to finish)

class VarAndValue {
  @BeanProperty
  val value = "";    
}

// Exiting paste mode, now interpreting.

defined class VarAndValue

scala> import reflect.runtime._, universe._
import reflect.runtime._
import universe._

scala> val str = typeOf[String]
str: reflect.runtime.universe.Type = String

scala> val ms = typeOf[VarAndValue].declarations filter (m => m.isMethod && m.name.decoded == "getValue")
warning: there were two deprecation warnings; re-run with -deprecation for details
ms: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(method getValue)

scala> val mm = ms.toList
mm: List[reflect.runtime.universe.Symbol] = List(method getValue)

scala> val m = mm.head.asInstanceOf[MethodSymbol]
m: reflect.runtime.universe.MethodSymbol = method getValue

scala> val t = m.returnType
t: reflect.runtime.universe.Type = java.lang.String

scala> println(t)
java.lang.String

scala> println(str)
String

scala> str == t
res2: Boolean = false

scala> str match { case `t` => }
scala.MatchError: String (of class scala.reflect.internal.Types$AliasNoArgsTypeRef)
  ... 33 elided

scala> str =:= t
res4: Boolean = true

scala> str match { case TypeRef(a,b,c) => (a,b,c) }
res5: (reflect.runtime.universe.Type, reflect.runtime.universe.Symbol, List[reflect.runtime.universe.Type]) = (scala.Predef.type,type String,List())

scala> t match { case TypeRef(a,b,c) => (a,b,c) }
res6: (reflect.runtime.universe.Type, reflect.runtime.universe.Symbol, List[reflect.runtime.universe.Type]) = (java.lang.type,class String,List())

根据您的目标,考虑一致的类型可以有不同的表示:

scala> typeOf[List[Int]]
res11: reflect.runtime.universe.Type = scala.List[Int]

scala> type X = List[Int]
defined type alias X

scala> typeOf[X].dealias
res12: reflect.runtime.universe.Type = List[scala.Int]

scala> res11 =:= res12
res13: Boolean = true

scala> res11 == res12
res14: Boolean = false

scala> typeOf[X] <:< res11
res15: Boolean = true

scala> typeOf[X] =:= res11
res16: Boolean = true

【讨论】:

  • 这是否意味着不应将类型用作地图的键?
  • 这取决于你在做什么,但不要指望别名类型比较相等。也许这就是你想要的。通常你对一致性感兴趣。
【解决方案2】:

原来这是比较类型的方法...

type1 match {
  case type2 => true
  case _ => false
}

它给出的答案与 type1==type 不同。

Scala 是一头奇怪的野兽。

【讨论】:

  • 不,你的type2是一个匹配任何东西的变量,和type2 @ _一样。小写表示模式中的 var。这是一个约定俗成的小缺点。使用反引号打败它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-03
  • 1970-01-01
  • 1970-01-01
  • 2011-11-18
  • 2018-03-26
相关资源
最近更新 更多