2012-02-23 4 views
6

Можно получить номер текущей строки на __LINE__ в Ruby или Perl. Например:Функция __LINE__ в Groovy

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

Есть та же функция в Groovy?

ответ

2

Не напрямую, но вы можете получить его через трассировку стека исключений (или 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

+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

1

Я не эксперт в Groovy, но я так не думаю. Я знаю, что Java и C# этого не делают.

Функция __LINE__ действительно начала помогать с отладкой на C. C не имеет исключений или многих других функций, которые имеют современные языки, но у них были макросы, которые компилятор мог расширить в любом месте кода, а именно мы нуждались в __FILE__, __LINE__ и т. д., чтобы сообщить нам, где мы были, когда случилось что-то плохое. Вот как работает assert в C и C++. JVM имеет очень хорошие инструменты отладки и в сочетании с assert и исключениями, вы можете легко определить, где что-то пошло не так (трассировка стека лучше, чем просто номер строки).

Я считаю, что причина, по которой Ruby и Perl имеют эти макросы, - это то, что они были созданы хакерами C. Я никогда не использовал ни один из этих языков, чтобы знать уровень поддержки отладки или насколько полезны макросы.

+0

Я могу подтвердить, что они мало используются. Обычный способ получения информации о кадре в Perl, будь то внутри отладчика или вне его, заключается в использовании функции 'caller' с номером фрейма в качестве аргумента. 0, где вы сейчас находитесь, 1 - ваш вызывающий, 2 - его * вызывающий и т. Д. Теперь это возвращает пакет, имя файла, строку, подпрограмму и множество других вещей. Таким образом, вы обычно используете функциональный интерфейс для получения этой информации, а не старые псевдомакросы '__FILE__' и' __LINE__'. – tchrist