Scala在编译时获取函数调用的行和文件

时间:2017-10-30 10:10:39

标签: scala macros jvm scala-2.12

我想要的是一个能够从调用它的位置打印行+文件的函数。

行为将是这样的:

log("x") //Called at line 15 of file Blax.scala

应打印

Blax.scala, line 15, message: x

类似于以下c ++代码:

    void _log(const char* message, const char* file, int line) { std::cout << file << ", " << line << ", message: " <<
message
<< "\n";}
    #define log(message) _log(message, __FILE__, __LINE__)

Scala可以做到这一点吗?是否有可能以半可读的方式进行,并且与未来和旧版本的编译器有些兼容?

我一直在尝试根据此处的宏部分实现类似的内容:https://docs.scala-lang.org/overviews/macros/overview.html

但是代码非常难以阅读,而且这些文章似乎并不涵盖与我需要的内容密切相关的任何内容。

我想我的问题可以分成两三个:

a)是否可以做任何类型的&#34;传统&#34;通过像函数一样调用宏来编译Scala中的代码?

所以基本上调用blax(a)在编译之前扩展为impl_blax(a, "b", __C__)

b)什么是&#34;推荐&#34;在Scala中编译时获取当前行号和文件名的方法?

c)如果a或b不可能,还有什么可以完成我想要的吗?

澄清:

是的,使用堆栈跟踪很容易做到这一点,但是抛出异常并获得堆栈跟踪是非常缓慢的,除了某些小众调试案例之外什么都不适合。我正在寻找一个无开销或低开销的解决方案,因此我要求使用宏的原因

编辑(为了回答标记):

@Seth Tisue将问题标记为重复

如果您将此标记为重复的问题解决了我的问题,我很乐意听到。原始问题中的一些链接导致404,最高投票答案的代码(未标记正确)似乎没有做任何与我想要的相关的事情,并且部分内容在scala中被标记为已弃用2.12 ......我确实偶然发现了这个问题,但我希望对这个问题更加明确,可能会产生一个以前与4年前的问题无关的答案。

1 个答案:

答案 0 :(得分:2)

除非您想将此作为练习并因此推出自己的解决方案,否则我建议的方法是重用已存在,已经过测试并满足您要求的库。

我找到了两位候选人:

1。源代码

sourcecode库基于宏,并在编译时提供元数据。

示例(取自他们调整到您问题的页面):

object Main extends App {
  def log(message: String)(implicit line: sourcecode.Line, file: sourcecode.File) = 
    println(s"${file.value}, line ${line.value}, message: $message")

  log("x")
}

这将打印:

  

/Users/jhoffmann/Development/sourcecode/src/main/scala/Main.scala,第5行,消息:x

2。阶-登录

作为标准替代方案,只需使用普通旧日志即可。看看scala-logging。使用logback作为后端,您可以在模式中使用%file%line%message

例如,请考虑logback.xml中配置的以下模式:

<pattern>%file, line %line, message: %message%n</pattern>

然后这段代码:

object Main extends App with LazyLogging {
  logger.info("x")
}

将打印:

  

Main.scala,第4行,消息:x