В коллекциях Scala 2.8, почему был добавлен тип Traversable выше Iterable?
Я знаю, что для Traversable
вам нужен только метод foreach
. Iterable
требуется метод iterator
.
Оба файла SID Scala 2.8 SID и бумага "Fighting Bitrot with Types" в основном молчат о том, почему добавлен Traversable
. SID только говорит: "Дэвид Макивер... предложил Traversable как обобщение Iterable".
Я смутно собрался из дискуссий по IRC, что он связан с возвратом ресурсов, когда обход коллекции завершается?
Возможно, это связано с моим вопросом. В TraversableLike.scala
есть некоторые нечетные определения функций, например:
def isEmpty: Boolean = {
var result = true
breakable {
for (x <- this) {
result = false
break
}
}
result
}
Я предполагаю, что есть веская причина, которая была написана не просто:
def isEmpty: Boolean = {
for (x <- this)
return false
true
}
Ответы
Ответ 1
Я спросил Дэвида Макивера об этом в IRC. Он сказал, что больше не помнит все причины, но они включали:
-
"итераторы часто раздражают... для реализации"
-
итераторы "иногда небезопасны (из-за установки/разрыва в начале и в конце цикла)"
-
Ожидаемая эффективность достигается за счет реализации некоторых вещей через foreach, а не с помощью итераторов (выигрыши необязательно пока еще не продемонстрированы с помощью текущего компилятора HotSpot)
Ответ 2
Я подозреваю, что одна из причин заключается в том, что гораздо проще написать конкретную реализацию для коллекции с абстрактным методом foreach
, чем для одного с абстрактным методом iterator
. Например, в С# вы можете написать реализацию метода GetEnumerator
IEnumerable<T>
, как если бы это был метод foreach
:
IEnumerator<T> GetEnumerator()
{
yield return t1;
yield return t2;
yield return t3;
}
(Компилятор генерирует соответствующий конечный автомат для управления итерацией через IEnumerator
.) В Scala вам нужно написать собственную реализацию Iterator[T]
для этого. Для Traversable
вы можете выполнить эквивалент вышеупомянутой реализации:
def foreach[U](f: A => U): Unit = {
f(t1); f(t2); f(t3)
}
Ответ 3
как раз относительно вашего последнего вопроса:
def isEmpty: Boolean = {
for (x <- this)
return false
true
}
Это грубо переведено компилятором на:
def isEmpty: Boolean = {
this.foreach(x => return false)
true
}
Таким образом, вы просто не можете вырваться из foreach, isEmpty всегда будет возвращать true.
Вот почему был создан "хакерский" Breakable, который вырывается из foreach, бросая Control-Exception, ловя его в breakable
и возвращает.