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
相关产品推荐
相关产品推荐

