5

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

行为将是这样的:

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) 是否可以通过像函数一样调用宏来在 Scala 中执行任何类型的“传统”代码内联?

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

b)在Scala编译时获取当前行号和文件名的“推荐”方式是什么?

c) 如果 a 或 b 都不可能,还有没有办法完成我想要的?

澄清:

是的,使用 Stack 跟踪很容易做到这一点,但是抛出异常并获取 Stack 跟踪的速度慢得令人难以忍受,并且除了某些特定的调试案例外,不适合任何事情。我正在寻找一种无开销或低开销的解决方案,因此我要求使用宏的解决方案

编辑(为了回答标志):

@Seth Tisue 将问题标记为重复

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

4

1 回答 1

6

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

我找到了两个候选人:

1. 源代码

源代码库基于宏并在编译时提供元数据。

示例(取自根据您的问题调整的页面):

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 日志记录

作为标准替代方案,只需使用普通的旧日志记录。看看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

于 2017-11-02T13:17:40.957 回答