Scala - разница между каждой петлей
Есть ли разница между двумя следующими утверждениями. Они достигают того же конца, правильно? Сопоставляют ли они один и тот же Java-код? Есть ли разница в производительности между ними или это просто вопрос предпочтения/удобочитаемости?
for (thing <- things) {
doSome(thing)
}
things.foreach(
thing =>
doSome(thing)
)
Ответы
Ответ 1
for
Постижения определяются как простые синтаксические переводы. Это чрезвычайно важно, поскольку это позволяет любому объекту работать с for
-пониманиями, он просто должен реализовать правильные методы.
IOW: спецификация языка Scala говорит, что первый фрагмент переводится во второй. Таким образом, если бы между этими двумя фрагментами была какая-либо разница, это было бы нарушением спецификации и, следовательно, очень серьезной ошибкой компилятора.
Некоторые люди просили и даже реализовали специальное обращение с определенными объектами (например, Range
s), но эти исправления всегда были отвергнуты с аргументом о том, что специальная обработка для специальных типов будет приносить пользу только этим специальным типам, тогда как Scala быстрее в целом принесет пользу всем.
Обратите внимание, что с помощью макросов, возможно, можно обнаружить, скажем, итерацию по сравнению с Range
чисто как простой цикл C style for
и преобразовать ее в цикл while
или прямую внутреннюю внутреннюю функцию, без изменить спецификацию или добавить специальный компилятор в компилятор.
Ответ 2
Они идентичны. Учитывая,
class Foreach {
val things = List(1,2,3)
def doSome(i: Int) { println(i) }
def one { for (thing <- things) { doSome(thing) } }
def two { things.foreach{ thing => doSome(thing) } }
}
байт-код
public void one();
Code:
0: aload_0
1: invokevirtual #40; //Method things:()Lscala/collection/immutable/List;
4: new #42; //class Foreach$$anonfun$one$1
7: dup
8: aload_0
9: invokespecial #46; //Method Foreach$$anonfun$one$1."<init>":(LForeach;)V
12: invokevirtual #52; //Method scala/collection/immutable/List.foreach:(Lscala/Function1;)V
15: return
public void two();
Code:
0: aload_0
1: invokevirtual #40; //Method things:()Lscala/collection/immutable/List;
4: new #55; //class Foreach$$anonfun$two$1
7: dup
8: aload_0
9: invokespecial #56; //Method Foreach$$anonfun$two$1."<init>":(LForeach;)V
12: invokevirtual #52; //Method scala/collection/immutable/List.foreach:(Lscala/Function1;)V
15: return
Ответ 3
Per scala-lang.org:
Как всегда, for-выражения могут использоваться в качестве альтернативного синтаксиса для выражений, включающих foreach, map, withFilter и flatMap, поэтому еще один способ печати всех элементов, возвращаемых итератором, будет:
для (elem < - it) println (elem)
"Альтернативный синтаксис" означает идентичность.