__Groovy中的线特征

__Groovy中的线特征,groovy,Groovy,可以通过Ruby或Perl中的\uuuuuuuuuuuuuuuuuuuu获取当前行号。 例如: print "filename: #{__FILE__}, line: #{__LINE__}" StackTraceElement getStackFrame(String debugMethodName) { def ignorePackages = [ 'sun.', 'java.lang', 'org.codehaus',

可以通过Ruby或Perl中的
\uuuuuuuuuuuuuuuuuuuu
获取当前行号。 例如:

print "filename: #{__FILE__}, line: #{__LINE__}"
 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)

Groovy中有相同的功能吗?

我不是Groovy的专家,但我不这么认为。我知道Java和C没有它

\uuuuuuuuuuuuuuuuuuuuuu
功能确实开始有助于在C中进行调试。C没有异常或现代语言的许多其他功能,但它确实有宏,编译器可以在代码中的任何地方进行扩展,这就是为什么我们需要
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu文件
,等,让我们知道我们在哪里时,坏事情发生了。这就是 Asvest在C和C++中的作用。JVM有非常好的调试工具,再加上
assert
和异常,您可以很容易地找出哪里出了问题(不管怎样,堆栈跟踪比仅仅一个行号要好得多)


我相信Ruby和Perl拥有这些宏的原因是因为它们是由C黑客创建的。我从未使用过这两种语言中的任何一种来了解调试支持的级别或宏的实际用途。

不直接使用,但您可以通过异常(或可丢弃的)堆栈跟踪来获得它。例如:

print "filename: #{__FILE__}, line: #{__LINE__}"
 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)

不过需要注意的是:像这样获取行号、文件名或方法的速度非常慢。

我可以确认它们并没有被广泛使用。在Perl中,无论是在调试器内部还是外部,获取帧信息的常规方法是使用
调用者
函数,并将帧编号作为参数。0是您现在所在的位置,1是您的调用者,2是他的调用者,等等。它现在返回该帧的包、文件名、行、子例程和一系列其他内容。因此,您通常会使用功能界面来获取这些信息,而不是旧的
\uuuuuuuuuuuuuuuuuuu文件\uuuuuuuuuuu
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu?Perl中的等价物(也就是说,通过
调用者
)非常快。Java堆栈跟踪可以非常深入,groovy甚至更深入。该方法只需花费一些时间来构建堆栈跟踪数据结构。查看以获得更深入的外观。使用它进行调试当然不会太慢,但在使用它之前,最好了解它的成本。