隐式提取 Scala 函数名称和参数
Extract Scala function name and params implicitly
我有以下代码:
def disableRules(someId: String) = Action.async { implicit req =>
Metrics.measureTime("disableRules") {
someFutureOpr(someId).map(_ => Ok)
.recover {
case e: Exception => handlerError(s"Failure occurred on disableRules request ${e.getMessage}", "disableRules")
}
}
}
def activeRules(someId: String) = Action.async { implicit req =>
Metrics.measureTime("activeRules") {
someFutureOpr2(someId).map(_ => Ok)
.recover {
case e: Exception => handlerError(s"Failure occurred on activeRules request ${e.getMessage}", "activeRules")
}
}
}
...
如您所见,我将 mesureTime
和 handleError
函数传递给它们 name 作为字符串的函数,有没有办法隐含地实现它,我的意思是它将采用函数名称,如果没有 - 有办法提取函数名称并打印它,也关于参数。
里面计算一下Metrics
:
object Metrics {
def currentMethodName() : String = Thread.currentThread.getStackTrace()(3).getMethodName
def measureTime(): Unit = {
println(currentMethodName)
}
}
然后例如:
def a1() = {
Metrics.measureTime()
}
def a2() = {
Metrics.measureTime()
}
将输出:
a1
a2
这样操作安全吗?
如果我们有:
def currentMethodName() : String = Thread.currentThread.getStackTrace.toList.mkString("\n")
我们得到:
java.lang.Thread.getStackTrace(Thread.java:1559)
HelloWorld1$Metrics$.currentMethodName(HelloWorld1.scala:69)
HelloWorld1$Metrics$.measureTime(HelloWorld1.scala:72)
HelloWorld1$.a1(HelloWorld1.scala:77)
HelloWorld1$.main(HelloWorld1.scala:103)
HelloWorld1.main(HelloWorld1.scala)
所以我们看到:
- 在索引 0 中我们得到
getStackTrace
。
- 在索引 1 中我们有
currentMethodName
。
- 在索引 2 中我们有
measureTime
。
因为 measureTime
不是堆栈跟踪的第一个方法,所以确定我们在堆栈跟踪中还有另一个元素。因此在你的情况下是的,它是安全的。
你可以用一个宏来解决这个问题(没有运行时反射):
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
class CaptureImpl(val c: blackbox.Context) {
import c.universe._
def describe[T: c.WeakTypeTag](
expr: c.Expr[T]
): c.Expr[String] = c.Expr[String](q"(${expr.tree.toString()})")
}
object CaptureMethod {
def apply[T](expr: T): String = macro CaptureImpl.describe[T]
}
示例:
object Test {
def foo(): String = "hello"
def bar(a: Int): Int = a
def baz(s: String): String = s
def main(args: Array[String]): Unit = {
println(CaptureMethod(foo()))
println(CaptureMethod(bar(1)))
println(CaptureMethod(baz("yes")))
}
}
产量:
Test.this.foo()
Test.this.bar(1)
Test.this.baz("yes")
我有以下代码:
def disableRules(someId: String) = Action.async { implicit req =>
Metrics.measureTime("disableRules") {
someFutureOpr(someId).map(_ => Ok)
.recover {
case e: Exception => handlerError(s"Failure occurred on disableRules request ${e.getMessage}", "disableRules")
}
}
}
def activeRules(someId: String) = Action.async { implicit req =>
Metrics.measureTime("activeRules") {
someFutureOpr2(someId).map(_ => Ok)
.recover {
case e: Exception => handlerError(s"Failure occurred on activeRules request ${e.getMessage}", "activeRules")
}
}
}
...
如您所见,我将 mesureTime
和 handleError
函数传递给它们 name 作为字符串的函数,有没有办法隐含地实现它,我的意思是它将采用函数名称,如果没有 - 有办法提取函数名称并打印它,也关于参数。
里面计算一下Metrics
:
object Metrics {
def currentMethodName() : String = Thread.currentThread.getStackTrace()(3).getMethodName
def measureTime(): Unit = {
println(currentMethodName)
}
}
然后例如:
def a1() = {
Metrics.measureTime()
}
def a2() = {
Metrics.measureTime()
}
将输出:
a1
a2
这样操作安全吗?
如果我们有:
def currentMethodName() : String = Thread.currentThread.getStackTrace.toList.mkString("\n")
我们得到:
java.lang.Thread.getStackTrace(Thread.java:1559)
HelloWorld1$Metrics$.currentMethodName(HelloWorld1.scala:69)
HelloWorld1$Metrics$.measureTime(HelloWorld1.scala:72)
HelloWorld1$.a1(HelloWorld1.scala:77)
HelloWorld1$.main(HelloWorld1.scala:103)
HelloWorld1.main(HelloWorld1.scala)
所以我们看到:
- 在索引 0 中我们得到
getStackTrace
。 - 在索引 1 中我们有
currentMethodName
。 - 在索引 2 中我们有
measureTime
。
因为 measureTime
不是堆栈跟踪的第一个方法,所以确定我们在堆栈跟踪中还有另一个元素。因此在你的情况下是的,它是安全的。
你可以用一个宏来解决这个问题(没有运行时反射):
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
class CaptureImpl(val c: blackbox.Context) {
import c.universe._
def describe[T: c.WeakTypeTag](
expr: c.Expr[T]
): c.Expr[String] = c.Expr[String](q"(${expr.tree.toString()})")
}
object CaptureMethod {
def apply[T](expr: T): String = macro CaptureImpl.describe[T]
}
示例:
object Test {
def foo(): String = "hello"
def bar(a: Int): Int = a
def baz(s: String): String = s
def main(args: Array[String]): Unit = {
println(CaptureMethod(foo()))
println(CaptureMethod(bar(1)))
println(CaptureMethod(baz("yes")))
}
}
产量:
Test.this.foo()
Test.this.bar(1)
Test.this.baz("yes")