【问题标题】:Scala - How to Convert Generic List To Array and avoid "No ClassTag available for T"Scala - 如何将通用列表转换为数组并避免“没有可用于 T 的 ClassTag”
【发布时间】:2020-09-29 06:38:33
【问题描述】:

我正在研究应该是一段微不足道的代码。我想获取一个列表,并将其转换为等效的数组:

import scala.collection.JavaConverters

object Help extends App {
  def f1[T](lst: List[T]) = {
    lst.toArray
  }

  val x = List(1, 2, 3)
  println(f1(x))
}

运行此代码给出:

"No ClassTag available for T"

我怎样才能避免这个问题;我来自 Python 背景,因此希望能够让我了解这里的机制。

谢谢!

【问题讨论】:

  • 这个:import scala.collection.JavaConverters 是不必要的。无论如何,这是一个微不足道且常见的问题,你只需要制作这个def f1[T : ClassTag](lst: List[T]): Array[T] = { - 顺便说一句,你为什么想要一个数组?数组是低级原语,不是集合,它们有很多像这样的问题,我建议远离它们,除非你需要使用它们。
  • 感谢@LuisMiguelMejíaSuárez,我实际上在使用 gson 库,它似乎与 Arrays 相比,它与 Scala Lists 相比更好。
  • 不要使用 gson,至少有 5 个很棒的 Scala 子库。为什么要使用与 scala 类型不兼容的 Java?

标签: java scala types jvm classtag


【解决方案1】:

尝试像这样添加隐式ClassTag参数

import scala.reflect.ClassTag

def f1[T](lst: List[T])(implicit ev: ClassTag[T]) = {
  lst.toArray
}

如果我们看一下toArray的签名,原因就很清楚了

def toArray[B >: A: ClassTag]: Array[B]

相当于

def toArray[B >: A](implicit ev: ClassTag[B]): Array[B]

所以你必须将隐式参数从f1 向下串接至toArray

如果您的回复能让我了解 机械师在这里

关键是要了解Array 不是真正的 Scala 集合。这一次,它不是Iterable的子类型

implicitly[Array[Int] <:< Iterable[Int]] // error

Array 和真正的 Scala 集合之间的另一个区别是,真正的 Scala 集合不需要 ClassTag。原因是 Scala 集合经历了类型擦除过程,这意味着运行时知道它是 List,但不区分 List[Int]List[String],例如。然而这不适用于Array。在运行时,Array[Int]Array[String] 之间确实存在差异。因此ClassTag 是一种发明来携带类型信息的机制,它只存在于编译时,一直到运行时,所以Array 可以具有Java 中的行为。

你会遇到其他的不同,例如

Array(42) == Array(42)  // false
List(42) == List(42)    // true

最佳做法是尽可能避免使用Array

【讨论】:

  • @finite_diffidence 不,为什么会这样?由于数组是 JVM 的原语,它们实际上不是通用的,而是存在不同类型的数组。类标签是在编译时创建的值,因此在运行时它知道哪个是实际类,因此它创建相应的数组。
  • @LuisMiguelMejíaSuárez,谢谢,确实很有见地。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-16
  • 1970-01-01
  • 2013-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多