在Scala中获取方法/函数/变量名称作为String

时间:2015-12-03 07:46:03

标签: scala literals

在Java中,我可以TheClass.class.getName()来获取一个我需要的类名,在某处(避免再次输入,避免拼写错误,明确记录依赖关系)。

我可以为Scala中的函数(或其他东西)执行相同的操作吗?

val theName : String = nameOf[aFunctionThatICanSeeHere]

3 个答案:

答案 0 :(得分:3)

对于班级名称:

val theName = classOf[TheClass].getName

classOf[TheClass]与Java中的TheClass.class相同。

对于方法等的名称,您可以使用reflection,就像在Java中一样。 (请注意,Scala反射API目前仍处于试验阶段。)

edit - 除了面向对象的编程语言之外,Scala也是一种函数式编程语言。您可以将函数作为值传递。例如:

class Thing {
  def method(x: Int): Int = x + 2
}

val thing = new Thing

// fn is a value that refers to a method
// similar to (but not really the same as) a method reference in Java
val fn = thing.method _

// you can call the method through fn
val result = fn(3) // same as thing.method(3)

答案 1 :(得分:2)

您可以使用scala-nameof来获取函数名称,变量名称,类成员名称或类型名称。它发生在编译时,因此不涉及反射,也不需要运行时依赖。

val theName = nameOf(aFunctionThatICanSeeHere _)

将编译为:

val theName = "aFunctionThatICanSeeHere"

答案 2 :(得分:1)

这使用ObjectWeb ASM库。这将提取给定类实例的所有方法。还有用于获取方法名称的代码。

import org.objectweb.asm.Type
import org.objectweb.asm.Type
import org.objectweb.asm.tree._
import org.objectweb.asm.util._
import java.lang.reflect.Method


case class ScalaMethod(name:String, returnType:Type, params:List[Param], parentClassName:String)
case class Param(paraName:String, paraType:Type)
object MethodReader {
  /*
   * stackoverflow.com/questions/7640617/how-to-get-parameter-names-and-types-via-reflection-in-scala-java-methods
   */
  def getMethods(c:AnyRef, is:java.io.InputStream) = {
    val cn = new ClassNode();
    val cr = new ClassReader(is);
    cr.accept(cn, 0);
    is.close();
    val methods = cn.methods.asInstanceOf[java.util.List[MethodNode]];
    var mList:List[ScalaMethod] = Nil
    if (methods.size > 0) for (i <- 1 to methods.size) {
      try {
        val m:MethodNode = methods.get(i-1)
        val argTypes:Array[Type] = Type.getArgumentTypes(m.desc);
        val vars = m.localVariables.asInstanceOf[java.util.List[LocalVariableNode]];
        var pList:List[Param] = Nil
        if (argTypes.length > 0 && vars.length > 0) for (i <- 1 to argTypes.length) {
          // The first local variable actually represents the "this" object in some cases
          val difference = if (vars.get(0).name == "this") 0 else 1
          pList = Param(vars.get(i-difference).name, argTypes(i-1)) :: pList
        }
        mList = ScalaMethod(m.name, Type.getReturnType(m.desc), pList.reverse, c.getClass.getCanonicalName):: mList
      } catch { 
        case e:Throwable => 
      }
    }
    mList.reverse
  }
  def getMethods(c, is):List[ScalaMethod] = {
    val t = Type.getType(c);
    val url = t.getInternalName() + ".class";
    val is = try {
      val cl = c.getClassLoader();
      val is = cl.getResourceAsStream(url);
      if (is == null) throw new IllegalArgumentException("Cannot find class: " + url);
      else is
    } catch {
      case e:IllegalArgumentException => 
        new java.io.FileInputStream(url)
    }
  }
}