【问题标题】:Initializing the factory at compile time在编译时初始化工厂
【发布时间】:2026-02-13 07:50:01
【问题描述】:

我有一个工厂,它应该根据名称返回一个实现。

    val moduleMap = Map(Modules.moduleName -> new ModuleImpl)
    def getModule(moduleName: String): Module =
        moduleMap.get(moduleName) match {
          case Some(m) => m
          case _ =>
            throw new ModuleNotFoundException(
              s"$moduleName - Module could not be found.")
        }

为了使每次调用“getModule”方法不创建实例,必须在引导类中初始化所有模块的映射。 我想摆脱手动执行此操作的需要(所有类都有一个独特的功能)。

我想到的选项列表:

  • 反射(我们可以使用 Scala 反射 API 或任何第三方 图书馆)
    • 自动化流程。
    • 需要在启动时立即初始化。
    • 反思是一种痛苦。
  • 元编程(ScalaMeta)+反射
    • 宏只改变代码,执行在以后发生。

我们可以将初始化过程移到编译时吗?

我知道编译器可以优化和替换代码,编译前的下一个片段

val a = 5 + 5

在编译编译器将那部分更改为 10 后,我们可以使用一些指令或其他工具在编译时评估和执行一些代码并只使用最终值吗?

【问题讨论】:

  • 或者你知道解决这个问题的另一种方法。

标签: scala reflection compilation factory scalameta


【解决方案1】:

您使用任何框架还是编写自己的框架?我回答了关于 Guice here 的类似问题。您也可以在没有 Guice 的情况下使用它:而不是 Module 您将拥有您的工厂,您需要从某个地方对其进行初始化,并且在初始化期间,您将使用反射填充您的地图

总的来说,我认为这是最简单的方法。或者,您可以编写宏,它只是替换反射初始化的一部分,但不确定它是否会给您带来一些好处(如果我理解您的问题,这个初始化只会在启动时发生一次)。

我不明白 scalameta 可以如何帮助你?可能,只有在您的所有实现都在您可用的源代码树中的情况下,您才能分析它并生成初始化(类似于宏)?可能,这会增加诸如更容易搜索实现的加号,但会增加减号:仅适用于您的源代码中的实现。

您的编译时优化示例不适用。在您的示例中,您谈到了编译时常量(即使使用算术也可能是一个问题,请参阅this 评论),但在您的问题中,您需要特定的运行时行为。所以compile time 可能只是从宏生成代码,或者从我的角度来看基于 scalameta。

【讨论】:

  • 我没有使用任何框架,我的实现非常简单,我可以手动描述模块初始化,但我想了解更多关于其他可能性的信息。)
  • scalaMeta,宏 - 这是一个很好的机会,但也有自己的问题。您无法调试使用宏、奇怪的语法、难以理解等添加的代码,而且您只需扩展或生成在 java 字节码 -> 机器命令中编译的新源(Class\Method\Variable)。这段代码仍然会被计算,当我初始化工厂时,生成的代码将被运行,jvm 花时间来计算值等等。我想知道我们是否可以在编译时运行一段代码并在运行时使用特定的值。无论如何,感谢资源的链接