2012-02-23 57 views
6

Ruby或Perl中可以通過__LINE__獲得當前行號。 例如:Groovy中的__LINE__功能

print "filename: #{__FILE__}, line: #{__LINE__}" 

Groovy中是否有相同的功能?

回答

2

不是直接的,但可以通過Exception(或Throwable)堆棧跟蹤來獲取它。例如:

StackTraceElement getStackFrame(String debugMethodName) { 
    def ignorePackages = [ 
     'sun.', 
     'java.lang', 
     'org.codehaus', 
     'groovy.lang' 
    ] 
    StackTraceElement frame = null 
    Throwable t = new Throwable() 
    t.stackTrace.eachWithIndex { StackTraceElement stElement, int index -> 
     if (stElement.methodName.contains(debugMethodName)) { 
      int callerIndex = index + 1 
      while (t.stackTrace[callerIndex].isNativeMethod() || 
        ignorePackages.any { String packageName -> 
         t.stackTrace[callerIndex].className.startsWith(packageName) 
        }) { 
       callerIndex++ 
      } 
      frame = t.stackTrace[callerIndex] 
      return 
     } 
    } 
    frame 
} 

int getLineNumber() { 
    getStackFrame('getLineNumber')?.lineNumber ?: -1 
} 

String getFileName() { 
    getStackFrame('getFileName')?.fileName 
} 

String getMethodName() { 
    getStackFrame('getMethodName')?.methodName 
} 

def foo() { 
    println "looking at $fileName:$lineNumber ($methodName)" 
} 

foo() 

// ==> looking at test.groovy:39 (foo) 

注意的一點是,雖然:讓行號,文件名或類似的方法,這是很

+0

爲什麼這麼慢? Perl中的等價物(意思是通過「caller」)非常快。 – tchrist 2012-02-23 18:51:50

+0

Java堆棧跟蹤可能相當深入,常規更是如此。方法[Throwable.fillInStackTrace](http://docs.oracle.com/javase/6/docs/api/java/lang/Throwable.html#fillInStackTrace%28%29)只需要一段時間來構建堆棧跟蹤數據結構體。查看http://stackoverflow.com/a/3980148/190201以獲得更深入的瞭解。用於調試肯定不會太慢,但在使用它之前最好意識到它的成本。 – ataylor 2012-02-23 19:10:56

1

我不是Groovy的專家,但我不這麼認爲。我知道Java和C#沒有它。

__LINE__功能真的開始幫助用C語言進行調試。C語言沒有例外或許多現代語言具有的其他功能,但它確實有宏,因此編譯器可以在代碼中的任何位置進行擴展,這就是爲什麼我們需要__FILE____LINE__等,讓我們知道發生什麼事情時發生的事情。這就是assert在C和C++中的工作原理。 JVM具有非常好的調試工具,並且與assert和異常結合使用,您可以非常容易地找出出現問題的地方(堆棧跟蹤無論如何都不僅僅是行號)。

我相信Ruby和Perl有這些宏的原因是因爲它們是由C黑客創建的。我從來沒有使用過這兩種語言中的任何一種來了解調試支持的級別或者宏的真實用處。

+0

我可以證實他們並沒有真正使用太多。在Perl中獲取關於幀的信息的正常方法,無論是在調試器內部還是在外部,都是使用「調用者」函數,幀號作爲參數。 0是你現在所在的位置,1是你的調用者,2是他*調用者等等。現在,它返回該框架的包,文件名,行,子例程以及其他一些東西。所以你通常會使用函數接口來獲取該信息,而不是舊的'__FILE__'和'__LINE__'僞宏。 – tchrist 2012-02-23 05:30:11