为什么Scala'String'对象的迭代器和'List [Int]'对象的迭代器在这里的行为不同?

时间:2018-07-19 05:33:53

标签: string scala scala-collections

我只是想探索REPL中String对象和List[Int]对象的迭代器的行为,测试如下所示:

scala> val list = List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)

scala> val itL = list.iterator
itL: Iterator[Int] = non-empty iterator

scala> List(8,5,list.size-13).map(itL.take(_).mkString)
res85: List[String] = List(12345678, 910111213, 141516)

scala> val st = "abcdefghijklmnop"
st: String = abcdefghijklmnop

scala> val itS = st.iterator
itS: Iterator[Char] = non-empty iterator

scala> List(8,5,st.size-13).map(itS.take(_).mkString)
res84: List[String] = List(abcdefgh, abcde, abc)

为什么迭代器的行为有所不同?在String对象的情况下,我的预期输出是:

List[String] = List(abcdefgh, ijklm, nop)

如果可能的话,有人可以通过示例进行解释。

另一个观察结果是:Range对象的迭代器的行为也与String对象完全相似 如下所示:

scala> val x = (1 to 16)
x: scala.collection.immutable.Range.Inclusive = Range 1 to 16

scala> val t = (1 to 16).iterator
t: Iterator[Int] = non-empty iterator

scala> List(8,5,x.size-13).map(t.take(_).mkString)
res103: List[String] = List(12345678, 12345, 123)

如果将Range转换为ListSet,则各个迭代器的行为将完全按照我的期望:

scala> val x1 = (1 to 16).toList
x1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)

scala> val t1 = x1.iterator
t1: Iterator[Int] = non-empty iterator

scala> List(8,5,x1.size-13).map(t1.take(_).mkString)
res104: List[String] = List(12345678, 910111213, 141516)

scala> val x2 = (1 to 16).toSet
x2: scala.collection.immutable.Set[Int] = Set(5, 10, 14, 1, 6, 9, 13, 2, 12, 7, 3, 16, 11, 8, 4, 15)

scala> val t2 = x2.iterator
t2: Iterator[Int] = non-empty iterator

scala> List(8,5,x2.size-13).map(t2.take(_).mkString)
res105: List[String] = List(51014169132, 12731611, 8415)

1 个答案:

答案 0 :(得分:8)

Iterator.take(n:Int) API documentation上有一个注释:

  

重用:调用此方法后,应丢弃被调用的迭代器,而仅使用返回的迭代器。使用旧的迭代器是不确定的,可能会发生更改,并且可能还会导致新的迭代器发生更改。

您似乎发现了一些“未定义”的行为。