Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for-comprehensions.md in russian #2854

Merged
merged 1 commit into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 82 additions & 11 deletions _ru/tour/for-comprehensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,54 +8,125 @@ next-page: generic-classes
previous-page: extractor-objects
---

Scala предлагает простую запись для выражения *последовательных преобразований*. Эти преобразования можно упростить используя специальный синтаксис `for выражения` (for comprehension), который записывается как `for (enumerators) yield e`, где `enumerators` относятся к списку перечислителей, разделенных точкой с запятой. Где отдельный такой "перечислитель" (*enumerator*) является либо генератором, который вводит новые переменные, либо фильтром. For-выражение вычисляет тело `e` (которое связанно с тем что генерирует *enumerator*) и возвращает последовательность вычислений.
Scala предлагает простую запись для выражения _последовательных преобразований_. Эти преобразования можно упростить используя специальный синтаксис `for выражения` (for comprehension), который записывается как `for (enumerators) yield e`, где `enumerators` относятся к списку перечислителей, разделенных точкой с запятой. Где отдельный такой "перечислитель" (_enumerator_) является либо генератором, который вводит новые переменные, либо фильтром. For-выражение вычисляет тело `e` (которое связанно с тем что генерирует _enumerator_) и возвращает последовательность вычислений.

Вот пример:

{% tabs for-comprehensions-01 class=tabs-scala-version %}
{% tab 'Scala 2' for=for-comprehensions-01 %}

```scala mdoc
case class User(name: String, age: Int)

val userBase = List(User("Travis", 28),
val userBase = List(
User("Travis", 28),
User("Kelly", 33),
User("Jennifer", 44),
User("Dennis", 23))

val twentySomethings = for (user <- userBase if (user.age >=20 && user.age < 30))
yield user.name // т. е. добавить результат к списку
val twentySomethings =
for (user <- userBase if user.age >=20 && user.age < 30)
yield user.name // т. е. добавить результат к списку

twentySomethings.foreach(name => println(name)) // выводит "Travis Dennis"
twentySomethings.foreach(println) // выводит "Travis Dennis"
```
`for`-выражение, используется с оператором `yield`, на самом деле создает `List`. Потому что мы указали `yield user.name` (то есть вывести имя пользователя), получаем `List[String]`. `user <- userBase` и есть наш генератор, а `if (user.age >=20 && user.age < 30)` - это фильтр который отфильтровывает пользователей, не достигших 30-летнего возраста.

{% endtab %}
{% tab 'Scala 3' for=for-comprehensions-01 %}

```scala
case class User(name: String, age: Int)

val userBase = List(
User("Travis", 28),
User("Kelly", 33),
User("Jennifer", 44),
User("Dennis", 23))

val twentySomethings =
for user <- userBase if user.age >=20 && user.age < 30
yield user.name // т. е. добавить результат к списку

twentySomethings.foreach(println) // выводит "Travis Dennis"
```

{% endtab %}
{% endtabs %}

`for`-выражение, используется с оператором `yield`, на самом деле создает `List`. Потому что мы указали `yield user.name` (то есть вывести имя пользователя), получаем `List[String]`. `user <- userBase` и есть наш генератор, а `if (user.age >=20 && user.age < 30)` - это фильтр который отфильтровывает пользователей, не достигших 30-летнего возраста.

Ниже приведен более сложный пример использования двух генераторов. Он вычисляет все пары чисел между `0` и `n-1`, сумма которых равна заданному значению `v`:

{% tabs for-comprehensions-02 class=tabs-scala-version %}
{% tab 'Scala 2' for=for-comprehensions-02 %}

```scala mdoc
def foo(n: Int, v: Int) =
for (i <- 0 until n;
j <- i until n if i + j == v)
j <- 0 until n if i + j == v)
yield (i, j)

foo(10, 10) foreach {
foo(10, 10).foreach {
case (i, j) =>
println(s"($i, $j) ") // выводит (1, 9) (2, 8) (3, 7) (4, 6) (5, 5)
println(s"($i, $j) ") // выводит (1, 9) (2, 8) (3, 7) (4, 6) (5, 5) (6, 4) (7, 3) (8, 2) (9, 1)
}
```

{% endtab %}
{% tab 'Scala 3' for=for-comprehensions-02 %}

```scala
def foo(n: Int, v: Int) =
for i <- 0 until n
j <- 0 until n if i + j == v
yield (i, j)

foo(10, 10).foreach {
(i, j) => println(s"($i, $j) ") // выводит (1, 9) (2, 8) (3, 7) (4, 6) (5, 5) (6, 4) (7, 3) (8, 2) (9, 1)
}
```

{% endtab %}
{% endtabs %}

Здесь `n == 10` и `v == 10`. На первой итерации `i == 0` и `j == 0` так `i + j != v` и поэтому ничего не выдается. `j` увеличивается еще в 9 раз, прежде чем `i` увеличивается до `1`. Без фильтра `if` будет просто напечатано следующее:
```scala

```scala
(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (0, 6) (0, 7) (0, 8) (0, 9) (1, 0) ...
```

Обратите внимание, что for-выражение не ограничивается только работой со списками. Каждый тип данных, поддерживающий операции `withFilter`, `map`, and `flatMap` (с соответствующими типами), может быть использован в for-выражении.

Вы можете обойтись без `yield` в for-выражении. В таком случае, результатом будет `Unit`. Это может быть полезным для выполнения кода основанного на побочных эффектах. Вот программа, эквивалентная предыдущей, но без использования `yield`:

{% tabs for-comprehensions-03 class=tabs-scala-version %}
{% tab 'Scala 2' for=for-comprehensions-03 %}

```scala mdoc:nest
def foo(n: Int, v: Int) =
for (i <- 0 until n;
j <- i until n if i + j == v)
j <- 0 until n if i + j == v)
println(s"($i, $j)")

foo(10, 10)
```

{% endtab %}

{% tab 'Scala 3' for=for-comprehensions-03 %}

```scala
def foo(n: Int, v: Int) =
for i <- 0 until n
j <- 0 until n if i + j == v
do println(s"($i, $j)")

foo(10, 10)
```

{% endtab %}
{% endtabs %}

## Дополнительные ресурсы

- Другие примеры "For comprehension" доступны [в книге Scala](/scala3/book/control-structures.html#for-expressions)
18 changes: 15 additions & 3 deletions _tour/for-comprehensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ num: 19
next-page: generic-classes
previous-page: extractor-objects

redirect_from:
redirect_from:
- "/tutorials/tour/for-comprehensions.html"
- "/tutorials/tour/sequence-comprehensions.html"
---

Scala offers a lightweight notation for expressing *sequence comprehensions*. Comprehensions have the form `for (enumerators) yield e`, where `enumerators` refers to a semicolon-separated list of enumerators. An *enumerator* is either a generator which introduces new variables, or it is a filter. A comprehension evaluates the body `e` for each binding generated by the enumerators and returns a sequence of these values.
Scala offers a lightweight notation for expressing _sequence comprehensions_. Comprehensions have the form `for (enumerators) yield e`, where `enumerators` refers to a semicolon-separated list of enumerators. An _enumerator_ is either a generator which introduces new variables, or it is a filter. A comprehension evaluates the body `e` for each binding generated by the enumerators and returns a sequence of these values.

Here's an example:

{% tabs for-comprehensions-01 class=tabs-scala-version %}
{% tab 'Scala 2' for=for-comprehensions-01 %}

```scala mdoc
case class User(name: String, age: Int)

Expand All @@ -33,8 +34,10 @@ val twentySomethings =

twentySomethings.foreach(println) // prints Travis Dennis
```

{% endtab %}
{% tab 'Scala 3' for=for-comprehensions-01 %}

```scala
case class User(name: String, age: Int)

Expand All @@ -50,6 +53,7 @@ val twentySomethings =

twentySomethings.foreach(println) // prints Travis Dennis
```

{% endtab %}
{% endtabs %}

Expand All @@ -59,6 +63,7 @@ Here is a more complicated example using two generators. It computes all pairs o

{% tabs for-comprehensions-02 class=tabs-scala-version %}
{% tab 'Scala 2' for=for-comprehensions-02 %}

```scala mdoc
def foo(n: Int, v: Int) =
for (i <- 0 until n;
Expand All @@ -73,6 +78,7 @@ foo(10, 10).foreach {

{% endtab %}
{% tab 'Scala 3' for=for-comprehensions-02 %}

```scala
def foo(n: Int, v: Int) =
for i <- 0 until n
Expand All @@ -83,10 +89,12 @@ foo(10, 10).foreach {
(i, j) => println(s"($i, $j) ") // prints (1, 9) (2, 8) (3, 7) (4, 6) (5, 5) (6, 4) (7, 3) (8, 2) (9, 1)
}
```

{% endtab %}
{% endtabs %}

Here `n == 10` and `v == 10`. On the first iteration, `i == 0` and `j == 0` so `i + j != v` and therefore nothing is yielded. `j` gets incremented 9 more times before `i` gets incremented to `1`. Without the `if` guard, this would simply print the following:

```scala
(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (0, 6) (0, 7) (0, 8) (0, 9) (1, 0) ...
```
Expand All @@ -97,6 +105,7 @@ You can omit `yield` in a comprehension. In that case, comprehension will return

{% tabs for-comprehensions-03 class=tabs-scala-version %}
{% tab 'Scala 2' for=for-comprehensions-03 %}

```scala mdoc:nest
def foo(n: Int, v: Int) =
for (i <- 0 until n;
Expand All @@ -105,9 +114,11 @@ def foo(n: Int, v: Int) =

foo(10, 10)
```

{% endtab %}

{% tab 'Scala 3' for=for-comprehensions-03 %}

```scala
def foo(n: Int, v: Int) =
for i <- 0 until n
Expand All @@ -116,9 +127,10 @@ def foo(n: Int, v: Int) =

foo(10, 10)
```

{% endtab %}
{% endtabs %}

## More resources

* Other examples of "For comprehension" in the [Scala Book](/overviews/scala-book/for-expressions.html)
- Other examples of "For comprehension" in the [Scala Book](/scala3/book/control-structures.html#for-expressions)
Loading