Для выражений в сравнении с foreach в Scala
Я прокладываю себе путь через Программирование в Scala, и хотя я испытываю соблазн смотреть на вещи с точки зрения Python, я не хотите запрограммировать "Python в Scala".
Я не совсем уверен, что делать с потоком управления: в Python мы используем for x in some_iterable
для смерти, и нам это нравится. Очень похожая конструкция существует в Scala, которую Одерский называет выражением for, вероятно, чтобы отличить ее от цикла Java for. Кроме того, Scala имеет атрибут foreach
(я думаю, это был бы атрибут, я не знаю достаточно о Scala, чтобы правильно его называть) для повторяющихся типов данных. Кажется, я не могу использовать foreach
для выполнения гораздо большего, чем вызов одной функции для каждого элемента в контейнере.
Это оставляет мне несколько вопросов. Во-первых, для выражений важные/сильно используемые конструкции в Scala, как и в Python, и во-вторых, когда следует использовать foreach
вместо выражения for (кроме очевидного случая вызова функции для каждого элемента контейнер)?
Надеюсь, я не ужасно двусмыслен или слишком застенчив, но я просто пытаюсь понять некоторые основы дизайна/языка в Scala (что пока кажется очень классным).
Ответы
Ответ 1
python использует for
в выражениях списков и выражений генератора. Они очень похожи на выражение scala for
:
это python
>>> letters = ['a', 'b', 'c', 'd']
>>> ints = [0, 1, 2, 3]
>>> [l + str(i) for l in letters for i in ints if i % 2 == 0]
['a0', 'a2', 'b0', 'b2', 'c0', 'c2', 'd0', 'd2']
это scala
scala> val letters = List('a', 'b', 'c', 'd')
scala> val ints = List(0, 1, 2, 3)
scala> for (l <- letters; i <- ints if i % 2 == 0) yield l.toString + i
res0: List[java.lang.String] = List(a0, a2, b0, b2, c0, c2, d0, d2)
Каждая конструкция может принимать несколько генераторов/итераторов, применять выражения фильтров и давать комбинированное выражение. В python (expr for v1 in gen1 if expr1 for v2 in gen2 if expr2)
примерно эквивалентен:
for v1 in gen1:
if expr1:
for v2 in gen2:
if expr2:
yield expr
В scala for (v1 <- gen1 if expr1; v2 <- gen2 if expr2) yield expr
примерно эквивалентно:
gen1.withFilter(expr1).flatMap(v1 => gen2.withFilter(expr2).map(v2 => expr))
Если вам нравится синтаксис python for x in xs
, вам, скорее всего, понравится выражение scala for
.
Scala имеет некоторые дополнительные синтаксические и трансляционные твисты. Синтаксис wise for
может использоваться с фигурными скобками, чтобы вы могли ставить утверждения на отдельные строки. Вы также можете выполнять назначения значений.
val res = for {
i <- 1 to 20; i2 = i*i
j <- 1 to 20; j2 = j*j
k <- 1 to 20; k2 = k*k
if i2 + j2 == k2
} yield (i, j, k)
Также v1 <- gen1
действительно выполняет соответствие case v1 => gen1
. Если нет совпадения, эти элементы игнорируются на итерации.
scala> val list = List(Some(1), None, Some(2))
scala> for (Some(i) <- list) yield i
res2: List[Int] = List(1, 2)
Я думаю, что for
занимает важное место на этом языке. Я могу сказать по тому, что в этой книге вы читаете целую главу (23)!
Ответ 2
Да, Scala для понимания (как они широко известны) используются много, но они действительно просто синтаксический сахар для определенной комбинации методов, и многие предпочитают называть эти методы напрямую, вместо использования синтаксического сахара.
Чтобы лучше понять Scala для понимания, см. этот вопрос. В частности, вы увидите, что for (x <- xs) f(x)
- это то же самое, что и xs.foreach(x => f(x))
.
Теперь вы отметите, что вы не очень хорошо используете метод foreach
, но я укажу, что почти все методы коллекций Scala (или могут быть реализованы) реализованы только с помощью foreach
, См. Документацию для Traversable
- все его методы могут быть реализованы только с помощью foreach
.
Обратите внимание, что Scala yield
не имеет сходства с Python yield
- вы можете искать этот вопрос.
Ответ 3
Благодаря поддержке вложенных итераций, фильтров и преобразований я бы сказал, что Scala for
является одной из сильных сторон языка и очень центральной. Я предпочитаю использовать его с помощью foreach
, map
и filter
.
Ответ 4
Предпросмотр - это функциональный стиль, в то время как for - это императивный стиль. Если вы когда-либо делали какой-либо lisp или схему, вы уже знакомы с функциональным программированием. Если вы этого не сделали, то сначала это может немного запутать. Первое, что я хотел бы сделать, - это прочитать синтаксис закрытия, который является анонимными функциями, которые вы передаете в таких вещах, как foreach. Как только вы поймете, что все это будет иметь смысл.
Ответ 5
На ваши вопросы в основном отвечают:
Scala Для понимания
Scala Доходность
Суммировать: это в значительной степени стилистично. Лично я выступаю за функциональную методологию, но предпочитаю лаконичность понимания при работе с вложенными циклами.