【问题标题】:Iteration over Scala tuples [duplicate]迭代Scala元组[重复]
【发布时间】:2013-09-11 04:41:22
【问题描述】:

在scala中,我们可以通过如下方式获得一个元组上的迭代器

val t = (1, 2)
val it = t.productIterator

甚至

it.foreach( x => println(x.isInstanceOf[Int]) )

返回 true,我们不能在不使用 asInstanceOf[Int] 的情况下对迭代器值进行简单操作,因为

it.foreach( x => println(x+1) )

返回错误:类型不匹配;找到:需要 Int(1):字符串

我了解 Integer 与 Int 的问题,但 isInstanceOf[Int] 的有效性仍然有些令人困惑。

对元组执行这些操作的最佳方法是什么?请注意,元组可以混合使用整数和双精度数等类型,因此转换为列表可能并不总是有效。

【问题讨论】:

  • 这个问题似乎更多是关于扁平化元组的元组
  • 如果您发现自己想要遍历一个元组并对每个值应用一个函数,这通常表明您一开始就不应该使用元组。元组不是集合,你不应该尝试这样使用它们。
  • 对,但有时你还是会得到元组,就像从数据库中读取一样,最简单的是直接处理它们。
  • 好吧,毕竟这可能不是最简单的;-)。

标签: scala iterator scala-collections


【解决方案1】:

元组不必是同质的,编译器也不会尝试跨元素应用魔法类型统一1。以(1, "hello") 为例,就是这样一个异构元组(Tuple2[Int,String])。

这意味着x 被键入为Any(而不是Int!)。尝试it.foreach( (x: Int) => println(x) ),使用原始元组,以获得更好的错误消息,指示迭代器统一元组元素的类型(它是Iterators[Any])。报告的错误应该类似于:

error: type mismatch;
 found   : (Int) => Unit
 required: (Any) => ?
       (1, 2).productIterator.foreach( (x: Int) => println(x) )

在这种特殊情况下,isInstanceOf[Int] 可用于细化类型 - 来自类型系统提供给我们的 Any - 因为我们知道,通过手动代码检查,它将使用给定的元组“安全”。

这里再看一下所涉及的迭代器/类型:

(1, 2)                         // -> Tuple2[Int,Int]
  .productIterator             // -> Iterator[Any]
  .map(_.asInstanceOf[Int])    // -> Iterator[Int]
  .foreach(x => println(x+1))

虽然我建议将元组视为同质元素的有限集合而不是序列,但可以使用与处理任何Iterator[Any] 时相同的规则,例如使用模式匹配(例如@987654333 @) 区分实际对象类型。 (在这种情况下,代码使用隐式 PartialFunction。)

(1, "hello").productIterator
  .foreach {
    case s: String => println("string: " + s)
    case i: Int => println("int: " + i)
  }

1 虽然在这种情况下可以让编译器统一类型,但这听起来像是一种特殊情况,需要额外的工作才能获得最小的收益。通常,像列表这样的序列——而不是元组——用于同质元素,编译器/类型系统正确地为我们提供了一个很好的改进,比如 List(1,2)(按预期键入为 List[Int])。

【讨论】:

  • 谢谢,我喜欢你用模式匹配来处理这个问题。
  • 模式匹配确实比isInstanceOf 更好——这就是为什么后者(故意)有这样一个长而丑陋的名字。它的风格更好,因为它以一种不易出错的方式统一了isInstanceOfasInstanceOf
  • 元组的productIterator 使用eachcase 创造奇迹!谢谢@user2246674
【解决方案2】:

还有另一种类型的 HList,即 tuple 和 List all-in-one。见shapeless

我认为,你可以接近你想要的:

import shapeless._
val t = 1 :: 2 :: HNil
val lst = t.toList
lst.foreach( x => println(x+1) )

【讨论】:

猜你喜欢
  • 2013-01-13
  • 1970-01-01
  • 2020-10-30
  • 2011-09-25
  • 1970-01-01
  • 2020-05-04
  • 1970-01-01
  • 1970-01-01
  • 2018-09-04
相关资源
最近更新 更多