我想要的是一个能够从调用它的位置打印行+文件的函数。
行为将是这样的:
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年前的问题无关的答案。
答案 0 :(得分:2)
除非您想将此作为练习并因此推出自己的解决方案,否则我建议的方法是重用已存在,已经过测试并满足您要求的库。
我找到了两位候选人:
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
作为标准替代方案,只需使用普通旧日志即可。看看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