对Scala元组的迭代

时间:2013-09-07 01:00:54

标签: scala iterator scala-collections

在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) )

返回错误:类型不匹配; found:Int(1)required:String

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

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

2 个答案:

答案 0 :(得分:3)

元组不必是同质的,编译器也不会尝试在元素 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]时可以使用相同的规则,例如使用模式匹配(例如match)区分实际对象类型。 (在这种情况下,代码使用隐式PartialFunction。)

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

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

答案 1 :(得分:1)

还有另一种类型HList,就像元组和List all-in-one。请参阅shapeless

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

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