Scala.js平台依赖的方法实现(或依赖注入)

时间:2017-01-16 23:50:57

标签: scala.js

tl; dr:像scalajs-java-time这样的库如何替换依赖项?

我遇到了Scala.js的依赖注入:

在共享代码中:

object Example {
  def method(...) = { ... dependsOnPlatform ... }
  val dependsOnPlatform = ???
}

这种天真的做法是:

val dependsOnPlatform = if(onJS) jsImplementation else jvmImplementaion

问题是人们经常无法为JVM编译jsImplementation,因为它依赖于Scala.js类;如果它使用反射或引用Java类,则可能无法完成fastOptJS的{​​{1}}。

鉴于jvmImplementaion必须是静态的,不能使用构造函数注入。

使用反射解决问题很容易,但Scala.js中不允许这样做。
它可以通过副作用来解决,但由于物体是静止的,因此很脆弱 依赖关系可以是object Example的隐式参数,但这需要额外的导入 这不是宏可以在不卷积构建过程的情况下解决的问题。

2 个答案:

答案 0 :(得分:3)

推荐的解决方案是使用在js/src/中以不同于jvm/src/的方式实现的顶级对象,但同时向两者公开相同的接口。然后,该对象的API通常可以从shared/src/代码中使用。此对象通常称为Platform,并使包为私有。

js/src/.../Platform.scala

package foo

private[foo] object Platform {
  def dependsOnPlatform(...) = {
    jsImplementation
  }
}

jvm/src/.../Platform.scala

package foo

private[foo] object Platform {
  def dependsOnPlatform(...) = {
    jvmImplementation
  }
}

shared/src/.../Platform.scala

package foo

object Example {
  def method(...) = {
    ...
    Platform.dependsOnPlatform(...)
    ...
  }
}

没有必要使用丑陋的阴影" hack也不写.java源文件,如@ acdenh的回答中所述。

答案 1 :(得分:0)

正确的解决方案是创建一个Java类和"阴影"它与Scala.js类。

在共享代码中:

method

然后在项目的Scala.js部分:

val dependsOnPlatform = new Injection

class InjectionForJVM { ... } //InjectionForJVM.scala

public class Injection extends InjectionForJVM { } //Injection.java

这两个class Injection { ... } //Injection.scala 类必须位于同一个包中并具有相同的接口 不要将Injection包装在任何对象或类中,因为InjectionForJVM.scala可能无法正确编译。 Injection.java可以使用反射和Java方法,因为InjectionForJVM.scala无法访问该类。也可以直接在Java中实现fastOptJS,但是谁可能想要这样做呢?

(确切地说,这并不是真正的影子,因为在任何情况下Scala.js都不存在Injection.java。在JVM上实际的类阴影是可能的,但通常是不可取的。)