You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala.js中泛型数组创建的通用实现方案求助

Scala.js 泛型数组创建的可行方案

问题场景

在JVM和Scala Native平台,以下代码可实现基于全类名字符串的泛型数组创建:

def newArray[A](fqcn: String, size: Int): Array[A] = {
  val clazz = Class.forName(fqcn)
  java.lang.reflect.Array.newInstance(clazz, size).asInstanceOf[Array[A]]
}

但Scala.js不支持java.lang.Class实例化,尝试用scala.scalajs.reflect.Reflect替代的代码对多数类无效:

val clazz = scala.scalajs.reflect.Reflect.lookupInstantiatableClass(fqcn)
  .getOrElse(throw new ClassNotFoundException(fqcn))
  .runtimeClass

解决方案

核心思路:利用Scala.js与JavaScript的映射关系

Scala.js编译后会将Scala数组转为JavaScript数组,因此可直接通过JS层面API动态创建数组,再转换为Scala数组。

基础实现(适用于无参构造的引用类型)

import scala.scalajs.js
import scala.scalajs.js.JSConverters._

def newArray[A](fqcn: String, size: Int): Array[A] = {
  // 通过全类名获取对应的JavaScript构造函数
  val jsConstructor = js.Dynamic.global.getOwnPropertyDescriptor(fqcn).value
  // 创建指定大小的JS数组,填充类实例
  val jsArray = js.Array.fill(size)(jsConstructor())
  // 转换为Scala数组并强制类型转换
  jsArray.toArray.asInstanceOf[Array[A]]
}

兼容基本数据类型的扩展实现

对于Int、Double等基本类型,可结合ClassTag实现更可靠的创建逻辑,同时保留引用类型的动态创建能力:

import scala.reflect.ClassTag
import scala.scalajs.js
import scala.scalajs.js.JSConverters._

// 建立全类名到ClassTag的映射表
val classTagMapping: Map[String, ClassTag[_]] = Map(
  "int" -> ClassTag.Int,
  "java.lang.Integer" -> ClassTag.Int,
  "double" -> ClassTag.Double,
  "java.lang.Double" -> ClassTag.Double,
  "boolean" -> ClassTag.Boolean,
  "java.lang.Boolean" -> ClassTag.Boolean
  // 可扩展其他基本类型及包装类
)

def newArray[A](fqcn: String, size: Int): Array[A] = {
  classTagMapping.get(fqcn) match {
    // 处理基本类型
    case Some(tag) => tag.newArray(size).asInstanceOf[Array[A]]
    // 处理引用类型
    case None =>
      val jsConstructor = js.Dynamic.global.getOwnPropertyDescriptor(fqcn).value
      js.Array.fill(size)(jsConstructor()).toArray.asInstanceOf[Array[A]]
  }
}

关于scala.scalajs.reflect的补充说明

若坚持使用反射API,需先在SBT配置中开启反射支持:

scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) }
scalaJSOptimizerOptions ~= { _.withReflection(true) }

但lookupInstantiatableClass仅能追踪显式标记为可反射、且有无参构造的类,适用场景有限,不如直接操作JS数组灵活。

内容的提问来源于stack exchange,提问作者Andriy Plokhotnyuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 19:07:15