2

在寻找使 Scala.js交叉构建项目的 JavaScript 和 JVM 端都可以访问 Java 库的方法时,请考虑以下实验:

想象一下,一个 Scala.js 项目需要高级矩阵数学功能,例如奇异值分解。虽然 JavaScript 世界有Numeric.js,而 JVM 世界有很多选择,但JAMA尤其是其中之一,在提出这个问题的时候还没有交叉构建 Scala.js 的解决方案。

我们有什么选择?

  1. 为 Scala.js 重新编写或移植一个矩阵库。
  2. 将 Numeric.js 外观和 JAMA 包装到一个通用的 Scala.js 接口中。
  3. 为 Numeric.js 编写外观,然后使用Nashorn编译它以获得 JVM 支持。
  4. 使用JSweet和时尚的 Scala.js 外观将 JAMA 转换为 JavaScript 。

这个问题反映了选项 4。

为 JSweet 转译器重新调整 JAMA,通过 npm将转译后的 JavaScript 发布为CommonJS 模块,并为 CommonJS 模块编写Scala.js 外观之后,Scala 代码现在可以在 JVM 端访问 Jama,并在 JS 端访问它的一个端口.

不幸的是,JVM端的核心数据结构在Scala语法中有type:double[][], Array[Array[Double]],但是JSweet将其转换为JavaScript数组类型,js.Array[js.Array[Double] ] 在 Scala.js 语法中。

现在,从 Scala.js 交叉构建的角度来看,存在两个名称相同、功能相同但完全不同且独立的库。

根据 Scala 语法,我们可以在 JS 端构造 3D 单位矩阵,如下所示:

new Matrix(
  js.Array[js.Array[Double]](
    new js.Array[Double](1.0, 0.0, 0.0),
    new js.Array[Double](0.0, 1.0, 0.0),
    new js.Array[Double](0.0, 0.0, 1.0)
   )
 )

在 JVM 端,我们编写:

new Matrix(
  Array[Array[Double]](
    new Array[Double](1.0, 0.0, 0.0),
    new Array[Double](0.0, 1.0, 0.0),
    new Array[Double](0.0, 0.0, 1.0)
  )
)

我们如何统一这两种实现方式?

将 js.Array 和 Array 等同起来有什么技巧吗?

你会建议一种完全不同的方法来使交叉构建的 Scala.js 项目可以访问 Java 库吗?

4

2 回答 2

2

让我从一个简单的问题开始:

将 js.Array 和 Array 等同起来有什么技巧吗?

不,没有这样的“技巧”。这些数据结构根本不同。js.Array的长度是可变的,并且可以使用其他属性进行修补。Array是 Java 的定长数组。如果有任何方法可以将它们等同起来,Scala.js 会为你做到这一点,就像它对Doubleand所做的那样number

统一 API 的一种相对简单的方法是在 Scala.js 代码中重建 JAMA 的API,其中每个类都是来自 JSweet 编译库的外观 JS 类的包装器。这使得 JAMA 的 Scala 级 API 在 Scala/JVM 和 Scala.js 之间完全等效。它确实需要编写一些代码来复制 API,但至少方法的主体不需要重写。

一种完全不同的方法,非常激进并且需要大量的工时,将分叉 JSweet 编译器以生成 Scala.js IR (.sjsir) 文件而不是 .js 文件。这样,您可以将 JAMA 的 JSweet 生成的 .sjsir 文件与应用程序的 Scala.js 生成的 .sjsir 文件链接在一起。这将提供最大的性能,因为 Scala.js 优化器将能够跨应用程序/库边界进行优化。

于 2018-06-26T09:53:09.730 回答
1

将 Java 库移植到 Scala.js 的秘诀:

  1. 获取 Java 源代码。
  2. 去掉 IO 和其他 JSweet 不兼容的功能。
  3. 使用 JSweet 将其编译为 Node.js 模块。
  4. 手动滚动一个 package.json 文件并在 npm 上发布 JSweet 转译器输出。
  5. 将 ScalaJS-bundler 添加到交叉编译的 Scala.js 项目中;包括第五步中的 CommonJS 模块。
  6. 在 build.sbt 的 JVM 依赖项中包含 Java 版本。
  7. 为 CommonJS 模块编写一个 Scala.js 外观。
  8. 使用原始 Java 库中的确切接口为 Scala.js 外观编写一个包装器。如果 Scala.js 支持,添加任何 IO 和其他 JSweet 不兼容的功能。
于 2018-07-01T04:14:59.070 回答