для выражений против foreach в Scala


Я работаю мой путь через программирование в Scala, и хотя я испытываю соблазн взглянуть на вещи с точки зрения Python, я не хочу программировать "Python в Scala."

Я не совсем уверен, что делать, насколько поток управления идет: в Python, мы используем for x in some_iterable до смерти, и мы любим его. Очень похожая конструкция существует в Scala, которую Одерский называет a для выражение, вероятно, чтобы отличить его от цикла Java for. Кроме того, у Scala есть foreach атрибут (я думаю, это будет атрибут, я не знаю достаточно о Scala, чтобы правильно назвать его) для итерационных типов данных. Не похоже, что я могу использовать foreach сделать гораздо больше, чем вызов одной функции для каждого элемента в контейнере, хотя.

это оставляет мне несколько вопросов. Во-первых, для выражений важны/сильно используются конструкции в Scala, как в Python, а во-вторых, когда я должен использовать foreach вместо выражения for (кроме очевидного случая вызова функция на каждом элементе контейнера)?

Я надеюсь, что я не буду ужасно двусмысленным или чрезмерным, но я просто пытаюсь Грок некоторые основы дизайна/языка в Scala (который кажется очень крутым до сих пор).

5 54

5 ответов:

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> 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 the (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

In скала for (v1 <- gen1 if expr1; v2 <- gen2 if expr2) yield expr примерно эквивалентно:

gen1.withFilter(expr1).flatMap(v1 => gen2.withFilter(expr2).map(v2 => expr))

если вы любите питон for x in xs синтаксис, вы, вероятно, любите scala for выражение.

Scala имеет некоторые дополнительные синтаксические и переводческие повороты. Синтаксис мудрый 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) об этом!

да, Scala для понимания (как они обычно известны) используются много, но на самом деле они просто синтаксический сахар для определенной комбинации методов, и многие предпочитают называть эти методы непосредственно вместо использования синтаксического сахара.

чтобы лучше понять Scala для понимания, пожалуйста, обратитесь к этот вопрос. В частности, вы увидите, что for (x <- xs) f(x) Это то же самое как xs.foreach(x => f(x)).

теперь, вы упомянули, что вы не кажетесь много пользы с foreach метод, но я отмечу, что почти все методы коллекций Scala реализованы (или могут быть реализованы) только с помощью foreach. Смотрите документацию для Traversable -- все его методы могут быть реализованы только foreach.

обратите внимание, что в Scala yield не имеет никакого сходства с питоном yield -- вы можете посмотреть это тоже вопрос.

С его поддержкой вложенных итераций, фильтров и преобразований, я бы сказал, что Scala for одна из сильных сторон языка и очень центральный. Я склонен отдавать предпочтение его использованию foreach,map и filter.

командлет foreach-это функциональный стиль, в то время как для императивном стиле. Если вы когда-либо делали Лисп или схему, вы уже знакомы с функциональным программированием. Если у вас нет, то это может быть немного запутанным на первый. Первое, что я бы сделал, это прочитать синтаксис закрытия, который является анонимными функциями, которые вы передаете в такие вещи, как foreach. Как только вы поймете, что все это будет иметь больше смысла.

на ваши вопросы в основном отвечают следующие:

скала для понимания

Scala Yield

подводя итог: это в значительной степени стилистика. Лично я предпочитаю функциональную методологию, но предпочитаю краткость понимания при работе с вложенными циклами.