Skip to content

Commit 5d13fe8

Browse files
Add context params in ru (#2878)
* Update compound-types.md in russian * Add ca-context-bounds.md, ca-context-parameters.md in russian * Add ca-context-bounds.md, ca-context-parameters.md in russian
1 parent f819c0e commit 5d13fe8

File tree

5 files changed

+340
-3
lines changed

5 files changed

+340
-3
lines changed

_overviews/scala3-book/ca-context-bounds.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Context Bounds
33
type: section
44
description: This page demonstrates Context Bounds in Scala.
5-
languages: [zh-cn]
5+
languages: [ru, zh-cn]
66
num: 62
77
previous-page: ca-context-parameters
88
next-page: ca-given-imports

_overviews/scala3-book/ca-context-parameters.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Context Parameters
33
type: section
44
description: This page demonstrates how to declare context parameters, and how the compiler infers them at call-site.
5-
languages: [zh-cn]
5+
languages: [ru, zh-cn]
66
num: 61
77
previous-page: ca-extension-methods
88
next-page: ca-context-bounds

_ru/scala3/book/ca-context-bounds.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
---
2+
layout: multipage-overview
3+
title: Контекстные границы
4+
scala3: true
5+
partof: scala3-book
6+
overview-name: "Scala 3 — Book"
7+
type: section
8+
description: В этой главе представлены контекстные границы в Scala 3.
9+
language: ru
10+
num: 62
11+
previous-page: ca-context-parameters
12+
next-page:
13+
---
14+
15+
Во многих ситуациях имя [контекстного параметра]({% link _overviews/scala3-book/ca-context-parameters.md %}#context-parameters)
16+
не нужно указывать явно, поскольку оно используется компилятором только в синтезированных аргументах для других параметров контекста.
17+
В этом случае вам не нужно определять имя параметра, а можно просто указать тип.
18+
19+
## Предыстория
20+
21+
Например, рассмотрим метод `maxElement`, возвращающий максимальное значение в коллекции:
22+
23+
{% tabs context-bounds-max-named-param class=tabs-scala-version %}
24+
25+
{% tab 'Scala 2' %}
26+
27+
```scala
28+
def maxElement[A](as: List[A])(implicit ord: Ord[A]): A =
29+
as.reduceLeft(max(_, _)(ord))
30+
```
31+
32+
{% endtab %}
33+
34+
{% tab 'Scala 3' %}
35+
36+
```scala
37+
def maxElement[A](as: List[A])(using ord: Ord[A]): A =
38+
as.reduceLeft(max(_, _)(using ord))
39+
```
40+
41+
{% endtab %}
42+
43+
{% endtabs %}
44+
45+
Метод `maxElement` принимает _контекстный параметр_ типа `Ord[A]` только для того,
46+
чтобы передать его в качестве аргумента методу `max`.
47+
48+
Для полноты приведем определения `max` и `Ord`
49+
(обратите внимание, что на практике мы будем использовать существующий метод `max` для `List`,
50+
но мы создали этот пример для иллюстрации):
51+
52+
{% tabs context-bounds-max-ord class=tabs-scala-version %}
53+
54+
{% tab 'Scala 2' %}
55+
56+
```scala
57+
/** Определяет, как сравнивать значения типа `A` */
58+
trait Ord[A] {
59+
def greaterThan(a1: A, a2: A): Boolean
60+
}
61+
62+
/** Возвращает максимальное из двух значений */
63+
def max[A](a1: A, a2: A)(implicit ord: Ord[A]): A =
64+
if (ord.greaterThan(a1, a2)) a1 else a2
65+
```
66+
67+
{% endtab %}
68+
69+
{% tab 'Scala 3' %}
70+
71+
```scala
72+
/** Определяет, как сравнивать значения типа `A` */
73+
trait Ord[A]:
74+
def greaterThan(a1: A, a2: A): Boolean
75+
76+
/** Возвращает максимальное из двух значений */
77+
def max[A](a1: A, a2: A)(using ord: Ord[A]): A =
78+
if ord.greaterThan(a1, a2) then a1 else a2
79+
```
80+
81+
{% endtab %}
82+
83+
{% endtabs %}
84+
85+
Обратите внимание, что метод `max` принимает контекстный параметр типа `Ord[A]`, как и метод `maxElement`.
86+
87+
## Пропуск контекстных аргументов
88+
89+
Так как `ord` - это контекстный параметр в методе `max`,
90+
компилятор может предоставить его для нас в реализации `maxElement` при вызове `max`:
91+
92+
{% tabs context-bounds-context class=tabs-scala-version %}
93+
94+
{% tab 'Scala 2' %}
95+
96+
```scala
97+
def maxElement[A](as: List[A])(implicit ord: Ord[A]): A =
98+
as.reduceLeft(max(_, _))
99+
```
100+
101+
{% endtab %}
102+
103+
{% tab 'Scala 3' %}
104+
105+
```scala
106+
def maxElement[A](as: List[A])(using Ord[A]): A =
107+
as.reduceLeft(max(_, _))
108+
```
109+
110+
Обратите внимание: поскольку нам не нужно явно передавать его методу `max`,
111+
мы можем не указывать его имя в определении метода `maxElement`.
112+
Это _анонимный параметр контекста_.
113+
114+
{% endtab %}
115+
116+
{% endtabs %}
117+
118+
## Границы контекста
119+
120+
Учитывая написанное выше, _привязка к контексту_ — это сокращенный синтаксис
121+
для выражения шаблона "параметр контекста, применяемый к параметру типа".
122+
123+
Используя привязку к контексту, метод `maxElement` можно записать следующим образом:
124+
125+
{% tabs context-bounds-max-rewritten %}
126+
127+
{% tab 'Scala 2 и 3' %}
128+
129+
```scala
130+
def maxElement[A: Ord](as: List[A]): A =
131+
as.reduceLeft(max(_, _))
132+
```
133+
134+
{% endtab %}
135+
136+
{% endtabs %}
137+
138+
Привязка типа `: Ord` к параметру типа `A` метода или класса указывает на параметр контекста с типом `Ord[A]`.
139+
Под капотом компилятор преобразует этот синтаксис в тот, который показан в разделе "Предыстория".
140+
141+
Дополнительные сведения о границах контекста см. в разделе ["Что такое границы контекста?"]({% link _overviews/FAQ/index.md %}#what-are-context-bounds) раздел FAQ по Scala.
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
---
2+
layout: multipage-overview
3+
title: Параметры контекста
4+
scala3: true
5+
partof: scala3-book
6+
overview-name: "Scala 3 — Book"
7+
type: section
8+
description: На этой странице показано, как объявлять параметры контекста и как компилятор выводит их на стороне вызова.
9+
language: ru
10+
num: 61
11+
previous-page: ca-extension-methods
12+
next-page: ca-context-bounds
13+
---
14+
15+
Scala предлагает две важные функции для контекстной абстракции:
16+
17+
- **Параметры контекста** позволяют указать параметры, которые на стороне вызова могут быть опущены программистом
18+
и должны автоматически предоставляться контекстом.
19+
- **Экземпляры given** (в Scala 3) или **неявные определения** (в Scala 2) — это термины,
20+
которые компилятор Scala может использовать для заполнения отсутствующих аргументов.
21+
22+
## Параметры контекста
23+
24+
При проектировании системы зачастую необходимо предоставлять контекстную информацию,
25+
такую как конфигурация или настройки, различным компонентам вашей системы.
26+
Одним из распространенных способов добиться этого является передача конфигурации
27+
в качестве дополнительного аргумента методам.
28+
29+
В следующем примере мы определяем кейс класс `Config` для моделирования некоторой конфигурации веб-сайта
30+
и передаем ее в различных методах.
31+
32+
{% tabs example %}
33+
{% tab 'Scala 2 и 3' %}
34+
35+
```scala
36+
case class Config(port: Int, baseUrl: String)
37+
38+
def renderWebsite(path: String, config: Config): String =
39+
"<html>" + renderWidget(List("cart"), config) + "</html>"
40+
41+
def renderWidget(items: List[String], config: Config): String = ???
42+
43+
val config = Config(8080, "docs.scala-lang.org")
44+
renderWebsite("/home", config)
45+
```
46+
47+
{% endtab %}
48+
{% endtabs %}
49+
50+
Предположим, что конфигурация не меняется на протяжении большей части нашей кодовой базы.
51+
Передача `config` каждому вызову метода (например `renderWidget`) становится очень утомительной
52+
и делает нашу программу более трудной для чтения, поскольку нам нужно игнорировать аргумент `config`.
53+
54+
### Установка параметров как контекстных
55+
56+
Мы можем пометить некоторые параметры наших методов как _контекстные_.
57+
58+
{% tabs 'contextual-parameters' class=tabs-scala-version %}
59+
{% tab 'Scala 2' %}
60+
61+
```scala
62+
def renderWebsite(path: String)(implicit config: Config): String =
63+
"<html>" + renderWidget(List("cart")) + "</html>"
64+
// ^
65+
// аргумент config больше не требуется
66+
67+
def renderWidget(items: List[String])(implicit config: Config): String = ???
68+
```
69+
70+
{% endtab %}
71+
{% tab 'Scala 3' %}
72+
73+
```scala
74+
def renderWebsite(path: String)(using config: Config): String =
75+
"<html>" + renderWidget(List("cart")) + "</html>"
76+
// ^
77+
// аргумент config больше не требуется
78+
79+
def renderWidget(items: List[String])(using config: Config): String = ???
80+
```
81+
82+
{% endtab %}
83+
{% endtabs %}
84+
85+
Начав секцию параметров с ключевого слова `using` в Scala 3 или `implicit` в Scala 2, мы сообщаем компилятору,
86+
что на стороне вызова он должен автоматически найти аргумент с необходимым типом.
87+
Таким образом, компилятор Scala выполняет **вывод термов**.
88+
89+
При вызове `renderWidget(List("cart"))` компилятор Scala увидит, что в области видимости есть терм типа `Config`
90+
(в нашем случае - `config`) и автоматически предоставит его для `renderWidget`.
91+
Таким образом, программа эквивалентна приведенной выше.
92+
93+
На самом деле, поскольку в реализации `renderWebsite` больше не нужно ссылаться на `config`,
94+
мы можем даже опустить его имя в подписи в Scala 3:
95+
96+
{% tabs 'anonymous' %}
97+
{% tab 'Только в Scala 3' %}
98+
99+
```scala
100+
// нет необходимости придумывать имя параметра
101+
// vvvvvvvvvvvvv
102+
def renderWebsite(path: String)(using Config): String =
103+
"<html>" + renderWidget(List("cart")) + "</html>"
104+
```
105+
106+
{% endtab %}
107+
{% endtabs %}
108+
109+
В Scala 2 именовать неявные параметры по-прежнему необходимо.
110+
111+
### Явное указание контекстных параметров
112+
113+
Мы увидели, как _абстрагироваться_ от контекстных параметров
114+
и что компилятор Scala может автоматически предоставлять нам аргументы.
115+
Но как мы можем указать, какую конфигурацию использовать для нашего вызова `renderWebsite`?
116+
117+
{% tabs 'explicit' class=tabs-scala-version %}
118+
{% tab 'Scala 2' %}
119+
120+
Мы явно указываем значение аргумента, как если бы это был обычный аргумент:
121+
122+
```scala
123+
renderWebsite("/home")(config)
124+
```
125+
126+
{% endtab %}
127+
{% tab 'Scala 3' %}
128+
129+
Подобно тому, как мы указали наш раздел параметров с помощью `using`,
130+
мы также можем явно указать контекстные параметры с помощью `using`:
131+
132+
```scala
133+
renderWebsite("/home")(using config)
134+
```
135+
136+
{% endtab %}
137+
{% endtabs %}
138+
139+
Явное предоставление контекстных параметров может быть полезно,
140+
когда у нас в области видимости есть несколько разных значений,
141+
подходящих по типу, и мы хотим убедиться в корректности передачи параметра методу.
142+
143+
Для всех остальных случаев, как мы увидим в следующем разделе,
144+
есть еще один способ ввести контекстуальные значения в область видимости.
145+
146+
## Экземпляры given (определения implicit в Scala 2)
147+
148+
Мы видели, что можем явно передавать аргументы в качестве контекстных параметров.
149+
Однако, если для определенного типа существует _единственное каноническое значение_,
150+
есть другой предпочтительный способ сделать его доступным для компилятора Scala:
151+
пометив его как `given` в Scala 3 или `implicit` в Scala 2.
152+
153+
{% tabs 'instances' class=tabs-scala-version %}
154+
{% tab 'Scala 2' %}
155+
156+
```scala
157+
implicit val config: Config = Config(8080, "docs.scala-lang.org")
158+
// ^^^^^^
159+
// это значение, которое выведет компилятор Scala
160+
// в качестве аргумента контекстного параметра типа Config
161+
```
162+
163+
{% endtab %}
164+
{% tab 'Scala 3' %}
165+
166+
```scala
167+
val config = Config(8080, "docs.scala-lang.org")
168+
169+
// это тип, который мы хотим предоставить для канонического значения
170+
// vvvvvv
171+
given Config = config
172+
// ^^^^^^
173+
// это значение, которое выведет компилятор Scala
174+
// в качестве аргумента контекстного параметра типа Config
175+
```
176+
177+
{% endtab %}
178+
{% endtabs %}
179+
180+
В приведенном выше примере мы указываем, что всякий раз,
181+
когда в текущей области видимости опущен контекстный параметр типа `Config`,
182+
компилятор должен вывести `config` в качестве аргумента.
183+
184+
Определив каноническое значение для типа `Config`,
185+
мы можем вызвать `renderWebsite` следующим образом:
186+
187+
```scala
188+
renderWebsite("/home")
189+
// ^
190+
// снова без аргумента
191+
```
192+
193+
Подробное руководство о том, где Scala ищет канонические значения, можно найти в [FAQ]({% link _overviews/FAQ/index.md %}#where-does-scala-look-for-implicits).
194+
195+
[reference]: {{ site.scala3ref }}/overview.html
196+
[blog-post]: /2020/11/06/explicit-term-inference-in-scala-3.html

_ru/scala3/book/ca-extension-methods.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ description: В этой главе представлена работа мет
99
language: ru
1010
num: 60
1111
previous-page: ca-contextual-abstractions-intro
12-
next-page:
12+
next-page: ca-context-parameters
1313
versionSpecific: true
1414
---
1515

0 commit comments

Comments
 (0)