迭代 Scala 元组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18668642/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:38:04  来源:igfitidea点击:

Iteration over Scala tuples

scalaiteratorscala-collections

提问by deepkimo

In scala, we can get an iterator over a tuple as follows

在scala中,我们可以得到一个元组上的迭代器,如下所示

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

and even

乃至

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

returns true, we cannot do simple operations on the iterator values without using asInstanceOf[Int], since

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

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

returns an error: type mismatch; found : Int(1) required: String

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

I understand the issue with Integer vs. Int, but still the validity of isInstanceOf[Int] is somewhat confusing.

我理解 Integer 与 Int 的问题,但 isInstanceOf[Int] 的有效性仍然有些混乱。

What is the best way to do these operations over tuples? Notice that the tuple can have a mix of types like integers with doubles, so converting to a list might not always work.

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

回答by user2246674

A tuple does not have to be homogenous and the compiler didn't try to apply magic type unification across the elements1. Take (1, "hello")as an example of such a a heterogenous tuple (Tuple2[Int,String]).

元组不必是同质的,并且编译器没有尝试跨元素应用魔法类型统一1。以(1, "hello")这种异质元组( Tuple2[Int,String])为例。

This means that xis typed as Any(not Int!). Try it.foreach( (x: Int) => println(x) ), with the original tuple, to get a better error message indicating that the iterator is notunified over the types of the tuple elements (it is an Iterators[Any]). The error reported should be similar to:

这意味着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) )

In this particular case isInstanceOf[Int]can be used to refine the type - from the Anythat the type-system gave us - because weknow, from manual code inspection, that it will "be safe" with the given tuple.

在这种特殊情况下,isInstanceOf[Int]可用于细化类型 - 从Any类型系统给我们的类型 - 因为我们知道,从手动代码检查中,它对于给定的元组是“安全的”。

Here is another look at the iterators/types involved:

这是所涉及的迭代器/类型的另一种看法:

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

While I would recommend treating tuples as finite sets of homogenous elementsand not a sequence, the same rules can be used as when dealing with any Iterator[Any]such as using pattern matching (e.g. match) that discriminates by the actual object type. (In this case the code is using an implicit PartialFunction.)

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

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


1While it might be possible to make the compiler unify the types in this scenario, it sounds like a special case that requires extra work for minimal gain. Normally sequences like lists - not tuples - are used for homogenous elements and the compiler/type-system correctly gives us a good refinement for something like List(1,2)(which is typed as List[Int]as expected).

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

回答by Arseniy Zhizhelev

There is another type HList, that is like tuple and List all-in-one. See shapeless.

还有另一种类型的 HList,就像元组和列表合二为一。见无形

I think, you can get close to what you want:

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

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