在Scala中,是否可以获取包含代码的成员/函数的名称?例如为了完成像
这样的代码def someFunc() {
Log(s"error $x occurred in function ${SomeScalaAPI.enclosingFunction}")
}
会产生一个字符串:
"错误X出现在函数someFunc"
中不诉诸creating and catching exceptions?我想假设,因为异常知道它们发生在哪里,这些信息可以通过一些Scala或Java反射API获得,或者通过一个聪明的编译时宏?
谢谢!
答案 0 :(得分:6)
一些宏观魔法的时间:
import language.experimental.macros
import reflect.macros.blackbox.Context
case class Location(filename: String, line: Int, column: Int, enclosingMethod : Option[String])
object PositionMacro {
def currentLocation: Location = macro impl
def impl(c: Context): c.Expr[Location] = {
import c.universe._
val pos = c.macroApplication.pos
val owner = c.internal.enclosingOwner //Old, deprecated way: c.enclosingMethod.symbol
val enclosingMethod = Some(owner).filter(_.isMethod).map(_.fullName)
c.Expr(q"Location(${pos.source.path}, ${pos.line}, ${pos.column}, ${enclosingMethod})")
}
}
你可以像这样使用它:
def test(): Unit = {
println(s"Called from ${PositionMacro.currentLocation}")
}
test()
// Called from Location(C:\Users\sschwets\AppData\Local\Temp\scratchPad.sc9.tmp,9,41,Some(A$A22.A$A22.test))
我将以下内容添加到我的build.sbt
文件中:
scalaVersion := "2.11.4"
libraryDependencies +=
"org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided"
注意:这是我第一个使用Scala 2.11接口和准引号的宏。它对我来说很好,但可能会格式化你的硬盘,清空你的银行帐户,宠坏你的孩子,愤怒你的猫或与你的妻子/丈夫/无论如何逃跑。所以请小心!
答案 1 :(得分:2)
您可以使用java:
java.lang.Thread.currentThread.getStackTrace()(1).getMethodName
示例:
scala> def aa = {println(java.lang.Thread.currentThread.getStackTrace()(1).getMethodName)}
aa: Unit
scala> aa
aa
但它不适用于函数 - 仅适用于方法:
scala> val zz = aa _
zz: () => Unit = <function0>
scala> zz()
aa
scala> val zzz = () => println(java.lang.Thread.currentThread.getStackTrace()(1).getMethodName)
zzz: () => Unit = <function0>
scala> zzz()
apply$mcV$sp
如果你正在寻找一些编译时宏,那就有一个类似的解决方案 - https://github.com/dk14/println-tracer;用法示例:
@trace class MyF {
def call(param: Int): Int = if (param == 0) param else call(param - 1)
def call2(param2: Int) = param2
def call3(param2: Int) = ???
}
(new MyF).call(2)
(new MyF).call2(666)
Try{(new MyF).call3(666)}
结果:
call(param = 2)
call(param = 1)
call(param = 0)
call = 0
call = 0
call = 0
call2(param2 = 666)
call2 = 666
call3(param2 = 666)
call3 = scala.NotImplementedError: an implementation is missing
它使用println
而不是logger(可修复)并且需要宏天堂库。所有参数/错误都会自动打印,这可能不是您想要的,但如果没有可用于日志记录的库,则可以将其用作模板。