2013-05-03 7 views
6

Używam następujący fragment kodu:Scala - iteratory i takeWhile

val it = List(1,1,1,2,2,3,3).iterator.buffered 
val compare = it.head 
it.takeWhile(_ == compare).toList 

i zwraca (1,1,1). Jeśli jednak uruchomię to jako:

val it = List(1,1,1,2,2,3,3).iterator.buffered 
it.takeWhile(_ == it.head).toList 

Dostaję (1,1). Dlaczego tak jest? Czy po wywołaniu head nie oceniono, czy wynik powinien być taki sam?

Odpowiedz

15

Ponieważ iterator jest zmienny, wartość it.head zależy od tego, kiedy jest oceniany.

Sprawdzanie implementation of takeWhile ujawnia, że ​​usuwa on głowicę iteratora przed stosując predykat.

W trzeciej iteracji it.head wyceniona z predykatu będzie 2, ponieważ trzeci element został już usunięty.

To jest ilustracja, dlaczego powinieneś preferować niezmienność. To wyklucza całą klasę nieoczywistych zachowań w ten sposób.

0

Dodawanie do @Ben James odpowiedź powyżej. Poniżej takeWhile kod metody (kredyty Ben):

def hasNext = hdDefined || tail.hasNext && { 
    hd = tail.next() //line 2 
    if (p(hd)) hdDefined = true 
    else tail = Iterator.empty 
    hdDefined 
} 

W trzeciej iteracji, po wierszu 2, wartość ta wynosi: hd=1 a pozostałe Iterator jest List(2,2,3,3). po wywołaniu p(hd), sprawdza iteratorową head, która w tym przypadku jest 2. Dlatego się psuje.