【问题标题】:Reinterpret List[Any] as a List[Int]将 List[Any] 重新解释为 List[Int]
【发布时间】:2015-03-19 16:19:41
【问题描述】:

我有一个List,我确信它只包含Int 成员,但该列表的类型是List[Any]。我需要对这个列表中的数字求和,但我不能使用 + 运算符,因为它没有在 Any 上定义。

scala> val l = List[Any](1, 2, 3)
l: List[Any] = List(1, 2, 3)

scala> l.foldLeft(0)(_ + _)
<console>:9: error: overloaded method value + with alternatives:
  (x: Int)Int <and>
  (x: Char)Int <and>
  (x: Short)Int <and>
  (x: Byte)Int
 cannot be applied to (Any)
              l.foldLeft(0)(_ + _)
                              ^

我尝试通过l.map(_.toInt) 将其转换为List[Int],但由于完全相同的原因当然失败了。

给定一个实际上是整数列表的List[Any],我如何将其转换为List[Int]

出于好奇,我是这样来的:

scala> val l = List(List("x", 1), List("y", 2))
l: List[List[Any]] = List(List(x, 1), List(y, 2))

scala> l.transpose
res0: List[List[Any]] = List(List(x, y), List(1, 2))

【问题讨论】:

  • 如果您确定您的列表只包含整数,您可以使用.map(_.asInstanceOf[Int]),但话又说回来,出于一个确切的原因,语法很糟糕。
  • 或者只是l.asInstanceOf[List[Int]],它没有运行时成本。
  • @RobertHarvey 在 scala api 中你很少能找到像 asInstanceOf 这样冗长的东西,这是因为类型转换是一种代码味道,在我看来,即使以 List[Any] 结尾也是一种代码味道,但当然这取决于提问者用例。
  • 我同意List[Any] 有点代码味道,所以我在问题中添加了一些信息来解决我是如何到达那里的。也许有更好的方法来做到这一点。
  • @Ryan,它们都很可怕,而且它们都会在运行时失败。如果您不确定演员阵容不会失败,您也不应该使用。

标签: list scala types casting type-conversion


【解决方案1】:

转换列表元素最安全的方法是使用collect

val l: List[Any] = List(1, 2, 3)

val l2: List[Int] = l collect { case i: Int => i }

collect 过滤和映射列表的元素,因此任何不是整数的元素都将被忽略。只有与 case 语句匹配的元素才会被包括在内。

OTOH,解决此问题的最佳方法是一开始就不要使用List[Any]。我会解决这个问题,而不是尝试投射。

【讨论】:

  • 我用我如何到达List[Any] 的信息更新了问题。我不确定在这种情况下是否可以避免,但也许?
  • 但是为什么你首先会有一个这样的异构列表呢?
  • 如果列表元素真的是一行的表示,最好使用元组而不是列表。
  • @CoryKlein,不会,但.unzip 会,而且它是类型安全的。
  • 天哪,我什么时候才能记住所有这些很棒的 lambda。谢谢@TravisBrown。我喜欢 Scala。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-20
  • 1970-01-01
  • 1970-01-01
  • 2013-01-01
  • 2018-02-04
  • 1970-01-01
  • 2016-12-26
相关资源
最近更新 更多