Scala中代码块的条件编译

3
我想知道在Scala中是否有一种条件性地排除代码块不被编译的方式,使用编译时标志(即C家族的#define的某种粗略等价物)。我知道没有直接的对应物,并且我认为Scala的宏也不是我需要的,所以我想知道是否有另一种方法来实现这一点。
具体来说,在我的当前情况下(我提供这个只是作为一个例子,因为我过去也遇到了类似的问题),我正在构建一个ScalaJS库。该库是一个前端组件,主要将被我的应用程序使用——该应用程序也使用ScalaJS。但是,我希望允许该组件在其他未使用ScalaJS的项目中由本机JavaScript调用。因此,我希望有一个用户可配置的标志,可以根据请求切换将符号导出到本机JavaScript。
在我的应用程序中,默认情况下不导出这些标志是没有意义的,因为唯一调用它的其他代码将是其他ScalaJS代码,因此导出符号的开销是毫无意义的。为如此微不足道的事情维护两个单独的代码分支也似乎是徒劳的。
这基本上是我所想的(当然是伪代码):
...

#if JS_EXPORT
@JSExport
#endif
case class componentProps(
    #if JS_EXPORT
    @(JSExport @field) 
    #endif
    val propertyOne: Int
    #if JS_EXPORT
    @(JSExport @field) 
    #endif
    val propertyTwo: String
)

...

我很清楚地知道这里没有预处理程序,上面的代码只是伪代码。我只是想知道是否有一种类似的实现方式,而不需要像使用反射那样产生不必要的开销(因为我确定这会比默认导出提供更大的性能损失)。
此外,我找到了这个问题:Scala中的条件编译。但那不是我需要的。

2
你可以通过 sbt 的 sourceGenerator 来构建自己的简单预处理器。 - sjrd
@sjrd 这将是一个有趣的项目,让我更深入地了解Scala。然而,这个问题也是为了衡量对这样的事情的普遍情绪,并确保我的想法没有错(即可能我误解了什么),因为对我来说这是显而易见的。你认为会有兴趣做这样的事情吗? - Ruslan
也许你可以尝试使用 elidable,虽然它和 #default 有所不同:https://dev59.com/rWoy5IYBdhLWcg3wsP_Q - 余杰水
2个回答

2

没有一种不是完全hack的方法可以在源代码内完成。

实现双JVM / JS项目的标准方式是将差异发生的源文件数量最小化,并手动处理这些文件(Li Haoyi的大多数项目都是这样 - 例如查看fastparse的结构); 或者有两个git分支具有两个变体并将所有更改从一个分支合并到另一个分支。


这正是我害怕听到的。我真的很惊讶,迄今为止还没有人为Scala开发预处理器,尤其是因为Scala拥有如此多的功能,适用于各种想象得到的用例,但是一个非常基本的功能(并且适用于相当数量的用例,尤其是桌面应用程序)却缺失了。除非是我错过了什么。然而,像这样的东西似乎至少作为sbt任务应该是自然而然的。 - Ruslan
尽可能减少平台特定代码所在的位置/源文件数量通常是一个好的实践,这与Scala.js完全无关 =) - Li Haoyi

1
针对您的特定情况,您不需要具体的源代码来完成此操作:Scala.js提供了scalajs-stubs库。这是一个面向JVM的库,包含Scala.js注解的存根注释(@JSExport等)。
您可以将其作为“provided”依赖项添加到您的JVM项目中,这样在运行时就不需要它了:
libraryDependencies +=
  "org.scala-js" %% "scalajs-stubs" % scalaJSVersion % "provided"

请注意,注释不是静态的,即它们甚至不会出现在.class文件中。
更多详细信息请参见scala-js.org(页面底部)。

谢谢!这很有帮助,但与我的情况没有直接关系,因为我的项目不是双目标ScalaJS/JVM;相反,它是两个版本的ScalaJS(一个用于导出以供原始Javascript使用,另一个用于其他ScalaJS代码的使用)。 - Ruslan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接