Scala3.4如何创建Array[T | Null]且无需ClassTag或asInstanceOf
问题:创建Array[T | Null]为何需要ClassTag?Scala 3.4有无替代方案?
我需要创建一个临时的Array[T | Null],其中类型参数T的上限为AnyRef。既然无论T是什么类型,数组在擦除后都会用Array[AnyRef]实现,为什么还必须依赖ClassTag?当前实现代码如下:
def method[T <: AnyRef](elements: Iterable[T])(using ctTorNull: ClassTag[T | Null]): T = { val array = elements.toArray[T | Null] ??? }
在Scala 3.4中,有没有办法不使用ClassTag也不使用asInstanceOf来实现相同需求?
为什么需要ClassTag?
虽然JVM在类型擦除后,所有T <: AnyRef对应的数组都会以Array[AnyRef]的形式存在,但JVM数组本身会保留运行时的元素类型信息——即使两个类型都继承自AnyRef,Array[A]和Array[B]在JVM层面的类型标识是不同的。Scala的ClassTag正是用来在运行时提供这份类型信息,让JVM能够正确创建对应类型的数组实例,避免类型不安全的操作。
Scala 3.4的替代方案
方案1:改用不需要ClassTag的可变集合
如果临时集合不强制要求是Array,可以换用不需要ClassTag的可变集合(比如ArrayBuffer)。mutable.ArraySeq仍需要ClassTag,但ArrayBuffer不需要,可通过IndexedSeq工厂创建:
def method[T <: AnyRef](elements: Iterable[T]): T = { val buffer = scala.collection.mutable.IndexedSeq.from[T | Null](elements) ??? }
方案2:利用输入集合自带的类型信息(仅适用于特定集合)
如果出于性能必须使用Array,且传入的集合暴露了底层数组的ClassTag(比如mutable.ArraySeq或mutable.ArrayStack,它们通过elemTag成员提供该信息),可以避免显式传入ClassTag参数:
def method[T <: AnyRef](elements: mutable.ArraySeq[T]): T = { val array = elements.toArray[T | Null](using elements.elemTag.asInstanceOf[ClassTag[T | Null]]) ??? }
这里基于一个前提:当T <: AnyRef时,T和T | Null的擦除类型是相同的。
内容的提问来源于stack exchange,提问作者Readren
相关产品推荐
相关产品推荐

