From 555b06f26fc343791860bd46e93319b81c81d001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D0=BE=D1=80=D1=81?= =?UTF-8?q?=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Tue, 4 Jul 2023 19:56:29 +0300 Subject: [PATCH] Update for-comprehensions.md in russian --- _ru/tour/for-comprehensions.md | 93 ++++++++++++++++++++++++++++++---- _tour/for-comprehensions.md | 18 +++++-- 2 files changed, 97 insertions(+), 14 deletions(-) diff --git a/_ru/tour/for-comprehensions.md b/_ru/tour/for-comprehensions.md index 5a2c538769..01da58caf6 100644 --- a/_ru/tour/for-comprehensions.md +++ b/_ru/tour/for-comprehensions.md @@ -8,42 +8,90 @@ 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) ... ``` @@ -51,11 +99,34 @@ foo(10, 10) foreach { Вы можете обойтись без `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) diff --git a/_tour/for-comprehensions.md b/_tour/for-comprehensions.md index c945055083..a211380230 100644 --- a/_tour/for-comprehensions.md +++ b/_tour/for-comprehensions.md @@ -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) @@ -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) @@ -50,6 +53,7 @@ val twentySomethings = twentySomethings.foreach(println) // prints Travis Dennis ``` + {% endtab %} {% endtabs %} @@ -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; @@ -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 @@ -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) ... ``` @@ -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; @@ -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 @@ -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)