【问题标题】:How to compare the return type of a method to a Scala native or TypeTag?如何将方法的返回类型与 Scala 本机或 TypeTag 进行比较?
【发布时间】:2020-06-12 22:07:31
【问题描述】:

所以,我正在使用 Scala 反射库,并尝试检查方法是否符合给定类型。为了简化,我试图只检查它的输出。

我现在拥有的是:

val returnType = methodSymbol.returnType
// returnType: reflect.runtime.universe.Type = java.lang.String

所以,我可以读到它是一个字符串,但它的类型很糟糕reflect.runtime.universe.Type。我到底如何比较检查这个返回类型是否是一个简单的字符串?我什至尝试使用很简单的 TypeTags,但是将 Type 转换为 TypeTag 是一项巨大的努力,我不相信这样简单的任务无法用更简单的方式完成。

那么,我怎样才能将它与字符串进行比较并简单地返回一个布尔值呢? 我想简单地调用toString() 并尝试将其解析回正常类型,但这对代码来说真的很恶心,IMO。另外,我不能简单地指定方法名称,因为我正在处理方法列表,以后还会有更多。

我已经看到了一些问题,甚至这个(在我看来,非常复杂)answer 关于如何将 Type 转换为 TypeTag,但是,我再次对这种复杂程度感到困惑琐碎的任务。我已经在考虑拔掉我稀少的头发了。帮助表示赞赏。

编辑:我已经设法对字符串本身进行了比较,但没有对返回字符串的方法进行比较。

为了比较String返回类型,我在做:

val returnType = methodSymbol.returnType
returnType =:= typeTag[String].tpe

但是,当我尝试使用继承和方法检查它时,使用<:<,它不起作用。澄清一下,B扩展了Trait A,类型签名是() => B,但是编码时我无法匹配

val typeSig = methodSymbol.typeSig
typeSig <:< typeTag[() => A].tpe

【问题讨论】:

  • 为什么需要根据字符串检查方法的返回类型? Scala 中通常不鼓励反射,因此很难做 “简单” 的事情也就不足为奇了。
  • 为什么不直接做returnType == typeOf[String]
  • 好吧,我不需要检查字符串。我需要确保给定对象中的某些方法符合预期的模式——我希望它们不接受任何参数作为输入,并返回给定的类型。字符串是一个简单的例子。我无法直接与 typeTag 进行比较,因为这种比较根本不起作用,因为 returnType 不是 TypeTag,如前所述。
  • typeOf 返回 Type,而不是 TypeTag,据我所知。看到这个 Scastie 游乐场:scastie.scala-lang.org/sQDO2hDJThyKuUiWaZWRmQ
  • Java 反射是否足以满足您的用例?它更容易使用。

标签: scala reflection scala-reflect


【解决方案1】:

如果您想使用 Strings 类型的类型,您应该解析它们

import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox

val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val str = "java.lang.String"
val tpe: Type = (tb.typecheck(tb.parse(s"type T = $str"), mode = tb.TYPEmode) match {
  case q"type T = $typ" => typ
}).tpe // String
tpe =:= typeOf[String] //true

(我只想做tb.typecheck(tb.parse(str/*, mode = ???*/), mode = tb.TYPEmode).tpe,但找不到如何使用运行时反射调用TypeParser而不是TermParser,这对应于tq"..."q"..."之间的区别,否则我得到@ 987654328@ 伴侣而不是 String 本身。当然tq"$str" 也会给出错误的类型,因为它是一个宏,它只能用于编译时文字:tq"java.lang.String"。)

【讨论】:

    【解决方案2】:

    也许不完全符合您的要求,但您可以在 Scala 中使用 java.lang.reflect

    import java.lang.reflect.Method
    
    class C {
      def doSomething(): String = {
        return "hello"
      }
      def doSomethingElse(): String = {
        return "bye"
      }
      def doNothing(): Int = {
        return 190
      }
    }
    
    val doSomethingMethod: Method = classOf[C].getMethods()(2)
    val doNothingMethod: Method = classOf[C].getMethods()(1)
    val doSomethingElseMethod: Method = classOf[C].getMethods()(0)
    
    // false
    doSomethingMethod.getReturnType.equals(doNothingMethod.getReturnType)
    
    // true
    doSomethingMethod.getReturnType.equals(doSomethingMethod.getReturnType)
    
    // you can compare the simple name, too, if that's easier
    println(s"'${doSomethingMethod.getReturnType.getSimpleName}'")
    // 'String'
    

    【讨论】:

      猜你喜欢
      • 2015-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多