2016-08-14 204 views
2

考慮下面的代碼:如何獲取使用Scala反射的方法的返回類型字符串?

object Foo{def foo(a:Int):List[(String, Int)] = ???} 

class Bar{def bar(a:Int, b:Any):Option[(String, Long)] = ???} 

鑑於無論是對象或類,我需要先找到方法名(似乎並不那麼困難)。

之後,對於每種方法,我想查找返回類型(不是Java類型)的Scala的字符串描述。因此,例如,對於Foo.foo,我需要字符串List[(String, Int)]Bar.bar,我需要字符串Option[(String, Long)]

我看到thisthis教程,但無法弄清楚。

編輯:這是一個基於評論我的嘗試:

class RetTypeFinder(obj:AnyRef) { 
    import scala.reflect.runtime.{universe => ru} 
    val m = ru.runtimeMirror(getClass.getClassLoader) 
    val im = m.reflect(obj) 
    def getRetType(methodName:String) = { 
    ru.typeOf[obj.type].declaration(ru.TermName(methodName)).asMethod.returnType 
    } 
} 
object A { def foo(a:Int):String = ??? } // define dummy object 
class B { def bar(a:Int):String = ??? } // define dummy class 
val a = new RetTypeFinder(A) 
a.getRetType("foo") // exception here 
val b = new RetTypeFinder(new B) 
b.getRetType("bar") // exception here 

我得到的錯誤是:

scala.ScalaReflectionException: <none> is not a method 
at scala.reflect.api.Symbols$SymbolApi$class.asMethod(Symbols.scala:228) 
at scala.reflect.internal.Symbols$SymbolContextApiImpl.asMethod(Symbols.scala:84) 
at cs.reflect.Test.getRetCls(Test.scala:11) 
... 

然而,這個工程(在REPL試過):

import scala.reflect.runtime.{universe => ru} 
val m = ru.runtimeMirror(getClass.getClassLoader) 

object A { def foo(a:Int):String = ??? } // define dummy object 

val im = m.reflect(A) 
ru.typeOf[A.type].declaration(ru.TermName("foo")).asMethod.returnType 

class B { def bar(a:Int):String = ??? } // define dummy class 

val im = m.reflect(new B) 
ru.typeOf[B].declaration(ru.TermName("bar")).asMethod.returnType 

我需要在第一種方式使用它,我不知道什麼對象/類將被傳遞。任何幫助將不勝感激。

+2

對於類:typeof運算(酒吧)。成員。(newTermName( 「富」))asMethod.returnType – Samar

+1

爲對象的作品相同,以及:'TYPEOF [Foo.type]。成員。( TermName(「foo」))。asMethod.returnType' – Kolmar

+0

@Kolmar請參閱我的編輯,瞭解更多詳細信息。 – Jus12

回答

1

一旦你有一個universe.Type可以使用的方式從意見得到其中的一個方法的返回類型:

import scala.reflect.runtime.{universe => ru} 

def getRetTypeOfMethod(tpe: ru.Type)(methodName: String) = 
    tpe.member(ru.TermName(methodName)).asMethod.returnType 

爲了得到一個universe.Type最簡單的方法是在一個隱含TypeTag捕捉到:

class RetTypeFinder[T <: AnyRef](obj: T)(implicit tag: ru.TypeTag[T]) { 
    def getRetType(methodName: String) = { 
    val tpe = tag.tpe 
    getRetTypeOfMethod(tpe)(methodName) 
    } 
} 

但是,如果你沒有一個TypeTag做,只是AnyRef類型的對象,你可以通過一個mirror來反映它。得到的Type會因失去了Java的類型擦除一些信息,但它仍然是足以讓名字的方法的返回類型,因爲這是由JVM反射支持:

class RetTypeFinder2(obj: AnyRef) { 
    def getRetType(methodName: String) = { 
    val mirror = ru.runtimeMirror(getClass.getClassLoader) 
    val tpe = mirror.reflect(obj).symbol.info 
    getRetTypeOfMethod(tpe)(methodName) 
    } 
} 

這兩種方法工作的優良你的問題:

scala> new RetTypeFinder(A).getRetType("foo") 
res0: reflect.runtime.universe.Type = String 

scala> new RetTypeFinder2(A).getRetType("foo") 
res1: reflect.runtime.universe.Type = String 

scala> new RetTypeFinder(new B).getRetType("bar") 
res2: reflect.runtime.universe.Type = String 

scala> new RetTypeFinder2(new B).getRetType("bar") 
res3: reflect.runtime.universe.Type = String 
+0

我不得不使用'RetTypeFinder2',因爲其他人沒有工作(同樣的錯誤)。我猜是因爲對象/類是在不同的項目中定義的。 – Jus12

相關問題