在Scala中迭代元组

11 浏览
0 Comments

在Scala中迭代元组

在Scala中,我们可以按以下方式获得元组的迭代器:\n

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

\n甚至可以这样做:\n

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

\n返回true,但在没有使用asInstanceOf[Int]的情况下,我们无法对迭代器的值进行简单操作,因为:\n

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

\n会返回错误:类型不匹配;找到:Int(1);需要:String\n我理解Integer与Int之间的问题,但isInstanceOf[Int]的有效性仍然有些令人困惑。\n如何以最佳方式对元组执行这些操作?请注意,元组可以包含整数和双精度浮点数等多种类型,因此转换为列表可能并不总是适用。

0
0 Comments

在Scala中,有一种类型叫做HList,它是tuple和List的结合体。你可以通过导入shapeless库来使用HList。下面的代码演示了如何将tuple转换为HList,并对HList进行迭代。

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

但是如果你已经有一个tuple,是否可以直接将其转换为HList,而不需要手动构建HList呢?在stackoverflow上有很多关于HList的问题,你可以参考这些问题来寻找答案。

我在stackoverflow上找到了这个问题的答案:github.com/milessabin/shapeless/blob/master/examples/src/main/…。是的,你可以将tuple转换为HList,反之亦然。

如果你喜欢某个答案,请记得接受它作为解决方案。

0
0 Comments

迭代Scala元组的问题出现的原因是元组不必是同质的,并且编译器没有尝试在元素之间应用魔术类型统一。以(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)

}

虽然在这种情况下,使编译器统一这种情况的类型可能是可能的,但这听起来像是一个特殊情况,需要额外的工作来获得最小的收益。通常,像列表这样的序列-而不是元组-被用于同质元素,并且编译器/类型系统正确地给出了我们对于List(1,2)这样的好的细化(它被类型化为List[Int],如预期的那样)。

谢谢,我喜欢你用模式匹配来处理这个问题的方式。

模式匹配确实是比isInstanceOf更好的样式-这就是为什么后者(故意)有一个如此冗长且丑陋的名称。它是更好的样式,因为它以一种较少容易出错的方式统一了isInstanceOf和asInstanceOf。

元组的productIterator使用each和case进行魔法操作!谢谢

0