0

在 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] 的有效性仍然有些令人困惑。

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

4

2 回答 2

5

元组不必是同质的,编译器也没有尝试在元素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]按预期输入)。

于 2013-09-07T01:23:50.323 回答
1

还有另一种类型 HList,类似于 tuple 和 List all-in-one。见无形

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

import shapeless._
val t = 1 :: 2 :: HNil
val lst = t.toList
lst.foreach( x => println(x+1) )
于 2013-09-07T10:35:25.007 回答