【问题标题】:Groovy, get enclosing function's name?Groovy,获取封闭函数的名称?
【发布时间】:2012-03-21 09:24:26
【问题描述】:

我正在使用 Groovy 1.8.4,试图获取封闭函数的名称...

def myFunction() {
  println functionName??
}

我试过delegatethisowner,Groovy 抱怨找不到这样的对象。

我还尝试了 Java hack new Exception().getStackTrace()[0].getMethodName(),但这只是打印 newInstance0

【问题讨论】:

  • 请问你想用方法名来完成什么?
  • 输出跟踪...我们正在构建 POC,代码经常更改,我们有一个方法可以在启动新函数时打印标题,我们希望名称来自函数本身,而不是将其作为参数传递,以防函数名称发生变化
  • stackoverflow.com/a/9417763/190201中有一个例子以及如何获取当前行号和文件名。
  • @ataylor 哦,伙计,这太恶心了!我暂时不用它处理,谢谢

标签: function reflection groovy introspection


【解决方案1】:
@CompileStatic
class LogUtils {
    // can be called the Groovy or Java way
    public static String getCurrentMethodName(){
        StackTraceElement[] stackTrace = StackTraceUtils.sanitize(new Throwable()).stackTrace
        stackTrace[2].methodName != 'jlrMethodInvoke' ? stackTrace[2].methodName : stackTrace[3].methodName
    }
}

【讨论】:

    【解决方案2】:
    import org.codehaus.groovy.runtime.StackTraceUtils
    
    def getCurrentMethodName(){
      def marker = new Throwable()
      return StackTraceUtils.sanitize(marker).stackTrace[1].methodName
    }
    
    def helloFun(){
       println( getCurrentMethodName() )
    }
    
    helloFun()
    

    输出:

    helloFun
    

    【讨论】:

    • 在闭包中调用 getCurrentMethodName() 时,会显示 doCall()。即 myArray.each { e -> println getCurrentMethodName(); }
    • stackTrace[1] 中的索引是否总是1
    • @cellepo,“调用堆栈”是您当前所在的所有函数(包括调用函数(以及那个调用函数等)。数字表示您在堆栈中的高度想去。使用 0 将返回“getCurrentMethodName”。使用 1 将返回“helloFun”。使用 2 将返回调用 helloFun 的函数的名称。等等。您可以在 @987654321 上阅读“调用堆栈”是什么@
    • 谢谢。是的,我知道调用堆栈是什么;我只是想在这里仔细检查索引。顺便说一句,我认为您的意思是“向下调用堆栈”,因为堆栈是自上而下的。不管调用堆栈如何在 IDE 或堆栈跟踪中可视化或打印,堆栈上除当前调用之外的调用都低于当前调用,因为当前调用位于堆栈顶部。
    【解决方案3】:

    groovy 的 StackTraceUtils.sanitize 怎么样?这是一个简单的例子:

    import org.codehaus.groovy.runtime.StackTraceUtils
    
    class A {
      def methodX() {
        methodY()
      }
    
      def methodY() {
        methodZ()
      }
    
      def methodZ() {
        def marker = new Throwable()
        StackTraceUtils.sanitize(marker).stackTrace.eachWithIndex { e, i ->
            println "> $i ${e.toString().padRight(30)} ${e.methodName}"
        }
      }
    
    }
    
    new A().methodX()
    

    上面粘贴到独立脚本test.groovy时的输出如下:

    $ groovy test.groovy 
    > 0 A.methodZ(test.groovy:13)      methodZ
    > 1 A.methodY(test.groovy:9)       methodY
    > 2 A.methodX(test.groovy:5)       methodX
    > 3 A$methodX.call(Unknown Source) call
    > 4 test.run(test.groovy:21)       run
    

    sanitize 方法从跟踪中过滤掉所有 groovy 内部 mumbo jumbo,并且干净的跟踪以及 ...stackTrace.find { } 应该会给您一个不错的开始。

    【讨论】:

    • 我将如何修改 methodZ 以便它返回立即调用函数,它只返回“1 A.methodY(test.groovy:9) methodY”
    【解决方案4】:

    你可以通过 stacktrace 来获取它,我已经能够通过以下方式获取它:

    groovy:000> def foo() { println Thread.currentThread().stackTrace[10].methodName }
    ===> true
    groovy:000> foo()
    foo
    groovy:000> class Foo {                                                             
    groovy:001>   def bar() { println Thread.currentThread().stackTrace[10].methodName }
    groovy:002> }
    ===> true
    groovy:000> new Foo().bar()
    bar
    

    【讨论】:

    • 是的,但您必须猜测堆栈跟踪深度 :) 并且不能保证在未来的 groovy 版本中保持不变
    • 以@doelerri 的代码为基础。你可以这样做:Thread.currentThread().stackTrace.find {it.className.startsWith("com.project...")}.methodName。在那里你可以做任何你觉得舒服的事情,以确保如果堆栈跟踪深度不保持一致,那么你会得到你的代码。
    • @JarredOlson 这些不只是黑客行为吗? Surprising Groovy 不提供这样的功能
    • @RaffiM:由于 Groovy 似乎没有,您可以随时提交 JIRA。
    • @All,Groovy 只是依赖于 Java。这不是你可以直接从 java 本身做的事情,没有完全相同的 hack。
    猜你喜欢
    • 1970-01-01
    • 2016-09-29
    • 1970-01-01
    • 1970-01-01
    • 2023-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多