Skip to content

Commit b41ee0e

Browse files
Update tour implicits in ru (#2887)
1 parent 41a18fe commit b41ee0e

File tree

2 files changed

+108
-71
lines changed

2 files changed

+108
-71
lines changed

_ru/tour/implicit-conversions.md

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,51 +8,45 @@ next-page: polymorphic-methods
88
previous-page: implicit-parameters
99
---
1010

11-
Неявные преобразование типа `S` к типу `T` задается неявным значением функционального типа `S =>T`, или неявным методом, который способен преобразовывать к значению требуемого типа.
11+
Неявные преобразования — это мощная функция Scala, применяемая в двух распространенных вариантах:
1212

13-
Неявное преобразование применяются в двух случаях:
13+
- разрешить пользователям предоставлять аргумент одного типа так, как если бы это был другой тип, чтобы избежать шаблонного.
14+
- в Scala 2 для предоставления дополнительных членов запечатанным классам (заменены [методами расширения][exts] в Scala 3).
1415

15-
* Если выражение `e` типа `S` не подходит под ожидаемый тип выражения `T`.
16-
* Если мы выбирая член `e.m`, где `e` является представителем типа `S`, при этом выбранное имя `m` не найдено среди доступных селекторов принадлежащих типу `S`.
17-
18-
В первом случае выполняется поиск приведения `c`, которое можно применить к `e` чтоб тип результата стал соответствовать ожидаемому `T`.
19-
Во втором случае выполняется поиск преобразования `c`, которое применимо к `e` и результат которого бы содержал член с именем `m`.
16+
### Детальный разбор
2017

21-
Если неявный метод `List[A] => Ordered[List[A]]` находится в области видимости, также как и неявный метод `Int => Ordered[Int]`, то следующая операция с двумя списками типа `List[Int]` является допустимой:
18+
{% tabs implicit-conversion-defn class=tabs-scala-version %}
19+
{% tab 'Scala 2' %}
2220

23-
```
24-
List(1, 2, 3) <= List(4, 5)
25-
```
21+
В Scala 2 неявное преобразование из типа `S` в тип `T` определяется либо [неявным классом]({% link _overviews/core/implicit-classes.md %}) `T`
22+
с одним параметром типа `S`, [неявным значением]({% link _tour/implicit-parameters.md %}), которое имеет тип функции `S => T`,
23+
либо неявным методом, преобразуемым в значение этого типа.
2624

27-
Неявный метод `Int => Ordered[Int]` предоставляется автоматически через `scala.Predef.intWrapper`. Ниже приведен пример объявления неявного метода `List[A] => Ordered[List[A]]`.
25+
{% endtab %}
26+
{% tab 'Scala 3' %}
2827

29-
```scala mdoc
30-
import scala.language.implicitConversions
28+
В Scala 3 неявное преобразование из типа `S` в тип `T` определяется [экземпляром `given`]({% link _tour/implicit-parameters.md %}), который имеет тип `scala.Conversion[S, T]`.
29+
Для совместимости со Scala 2 их также можно определить неявным методом (подробнее читайте во вкладке Scala 2).
3130

32-
implicit def list2ordered[A](x: List[A])
33-
(implicit elem2ordered: A => Ordered[A]): Ordered[List[A]] =
34-
new Ordered[List[A]] {
35-
//заменить на более полезную реализацию
36-
def compare(that: List[A]): Int = 1
37-
}
38-
```
31+
{% endtab %}
32+
{% endtabs %}
3933

40-
Неявно импортируемый объект `scala.Predef` объявляет ряд псевдонимов для часто используемым типов (например, `scala.collection.immutable.Map` использует псевдоним `Map`) и методов (например, `assert`), а также делает доступным целую серию неявных преобразований.
34+
Неявные преобразования применяются в двух случаях:
4135

42-
Например, при вызове Java метода, который ожидает `java.lang.Integer`, вместо него вы можете свободно использовать `scala.Int`. Потому что Predef включает в себя следующие неявные преобразования:
36+
1. Если выражение `e` имеет тип `S` и `S` не соответствует ожидаемому типу выражения `T`.
37+
2. При выборе `e.m`, где `e` типа `S`, если селектор `m` не указывает на элемент `S`.
4338

44-
```scala mdoc
45-
import scala.language.implicitConversions
39+
В первом случае ищется конверсия `c`, применимая к `e` и тип результата которой соответствует `T`.
4640

47-
implicit def int2Integer(x: Int): Integer =
48-
Integer.valueOf(x)
49-
```
41+
Примером является передача `scala.Int`, например `x`, методу, который ожидает `scala.Long`.
42+
В этом случае вставляется неявное преобразование `Int.int2long(x)`.
5043

51-
Компилятор предупреждает при компиляции об обнаружении неявных преобразований, т.к. неявные преобразования могут иметь разные подводные камни (особенно если использовать их без разбора).
44+
Во втором случае ищется преобразование `c`, применимое к `e` и результат которого содержит элемент с именем `m`.
5245

53-
Чтоб отключить предупреждения выполните одно из следующих действий:
46+
Примером является сравнение двух строк `"foo" < "bar"`.
47+
В этом случае `String` не имеет члена `<`, поэтому вставляется неявное преобразование `Predef.augmentString("foo") < "bar"`
48+
(`scala.Predef` автоматически импортируется во все программы Scala).
5449

55-
* Импортируйте `scala.language.implicitConversions` в области видимости, где объявлены неявные преобразования.
56-
* Вызывайте компилятор с ключом `-language:implicitConversions`.
50+
Дополнительная литература: [Неявные преобразования (в книге Scala)]({% link _overviews/scala3-book/ca-implicit-conversions.md %}).
5751

58-
В таком случае при преобразовании компилятором не будет выдаваться никаких предупреждений.
52+
[exts]: {% link _overviews/scala3-book/ca-extension-methods.md %}

_ru/tour/implicit-parameters.md

Lines changed: 81 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,111 @@
11
---
22
layout: tour
3-
title: Неявные Параметры
3+
title: Контекстные параметры, также известные, как неявные параметры
44
partof: scala-tour
55
num: 26
66
language: ru
77
next-page: implicit-conversions
88
previous-page: self-types
99
---
1010

11-
Метод может иметь список _неявных_ параметров, помеченный ключевым словом _implicit_ в начале списка параметров. Если параметры в этом списке не передаются как обычно, то Scala будет искать, где можно получить неявное значение требуемого типа, и если найдет, то передаст его автоматически.
11+
Метод может иметь список _контекстных параметров_ (_contextual parameters_),
12+
также называемых _неявными параметрами_ (_implicit parameters_) или, точнее, _имплицитами_ (_implicits_).
13+
Списки параметров, начинающиеся с ключевого слова `using` (или `implicit` в Scala 2), задают контекстные параметры.
14+
Если сторона вызова явно не предоставляет аргументы для таких параметров,
15+
Scala будет искать неявно доступные `given` (или `implicit` в Scala 2) значения правильного типа.
16+
Если можно найти подходящие значения, то они автоматически передаются.
1217

13-
Места, где Scala будет искать эти параметры, делятся на две категории:
14-
15-
* Скала сначала будет искать неявные параметры, доступ к которым можно получить напрямую (без префикса) в месте вызова метода в котором запрошены неявные параметры.
16-
* Затем он ищет членов, помеченных как implicit во всех объектах компаньонах, связанных с типом неявного параметра.
18+
Лучше всего вначале показать это на небольшом примере.
19+
Мы определяем интерфейс `Comparator[A]`, который может сравнивать элементы типа `A`,
20+
и предоставляем две реализации для `Int`-ов и `String`-ов.
21+
Затем мы определяем метод `max[A](x: A, y: A)`, который возвращает больший из двух аргументов.
22+
Так как `x` и `y` имеют абстрактный тип, в общем случае мы не знаем, как их сравнивать, но можем запросить соответствующий компаратор.
23+
Поскольку обычно для любого заданного типа существует канонический компаратор `A`,
24+
то мы можем объявить их как _заданные_ (_given_) или _неявно_ (_implicitly_) доступные.
1725

18-
Более подробное руководство, о том где scala ищет неявные значения можно найти в [FAQ](/tutorials/FAQ/finding-implicits.html)
26+
{% tabs implicits-comparator class=tabs-scala-version %}
1927

20-
В следующем примере мы определяем метод `sum`, который вычисляет сумму элементов списка, используя операции `add` и `unit` моноида. Обратите внимание, что неявные значения не могут находится выше уровнем.
28+
{% tab 'Scala 2' for=implicits-comparator %}
2129

2230
```scala mdoc
23-
abstract class Monoid[A] {
24-
def add(x: A, y: A): A
25-
def unit: A
31+
trait Comparator[A] {
32+
def compare(x: A, y: A): Int
2633
}
2734

28-
object ImplicitTest {
29-
implicit val stringMonoid: Monoid[String] = new Monoid[String] {
30-
def add(x: String, y: String): String = x concat y
31-
def unit: String = ""
35+
object Comparator {
36+
implicit object IntComparator extends Comparator[Int] {
37+
def compare(x: Int, y: Int): Int = Integer.compare(x, y)
3238
}
33-
34-
implicit val intMonoid: Monoid[Int] = new Monoid[Int] {
35-
def add(x: Int, y: Int): Int = x + y
36-
def unit: Int = 0
37-
}
38-
39-
def sum[A](xs: List[A])(implicit m: Monoid[A]): A =
40-
if (xs.isEmpty) m.unit
41-
else m.add(xs.head, sum(xs.tail))
42-
43-
def main(args: Array[String]): Unit = {
44-
println(sum(List(1, 2, 3))) // использует intMonoid неявно
45-
println(sum(List("a", "b", "c"))) // использует stringMonoid неявно
39+
40+
implicit object StringComparator extends Comparator[String] {
41+
def compare(x: String, y: String): Int = x.compareTo(y)
4642
}
4743
}
44+
45+
def max[A](x: A, y: A)(implicit comparator: Comparator[A]): A =
46+
if (comparator.compare(x, y) >= 0) x
47+
else y
48+
49+
println(max(10, 6)) // 10
50+
println(max("hello", "world")) // world
51+
```
52+
53+
```scala mdoc:fail
54+
// не компилируется:
55+
println(max(false, true))
56+
// ^
57+
// error: could not find implicit value for parameter comparator: Comparator[Boolean]
4858
```
4959

50-
`Monoid` определяет здесь операцию под названием `add`, которая сочетает два элемента типа `A` и возвращает сумму типа `A`, операция `unit` позволяет вернуть отдельный (специфичный) элемент типа `A`.
60+
Параметр `comparator` автоматически заполняется значением `Comparator.IntComparator` для `max(10, 6)`
61+
и `Comparator.StringComparator` для `max("hello", "world")`.
62+
Поскольку нельзя найти неявный `Comparator[Boolean]`, вызов `max(false, true)` не компилируется.
5163

52-
Чтобы показать, как работают неявные параметры, сначала определим моноиды `stringMonoid` и `intMonoid` для строк и целых чисел, соответственно. Ключевое слово `implicit` указывает на то, что этот объект может быть использован неявно.
64+
{% endtab %}
5365

54-
Метод `sum` принимает `List[A]` и возвращает `A`, который берет начальное `A` из `unit` и объединяет каждое следующее `A` в списке используя `add` метод. Указание параметра `m` в качестве неявного параметра подразумевает, что `xs` параметр будет обеспечен тогда, когда при вызове параметра метода Scala сможет найти неявный `Monoid[A]` чтоб его передать в качестве параметра `m`.
66+
{% tab 'Scala 3' for=implicits-comparator %}
5567

56-
В нашем `main` методе мы вызываем `sum` дважды и предоставляем только `xs` параметр. Теперь Scala будет искать неявное значение в указанных ранее областях видимости. Первый вызов `sum` проходит с использованием `List[Int]` в качестве `xs`, это означает, что элемент `A` имеет тип `Int`. Неявный список параметров с `m` опущен, поэтому Scala будет искать неявное значение типа `Monoid[Int]`. Первое правило поиска гласит
68+
```scala
69+
trait Comparator[A]:
70+
def compare(x: A, y: A): Int
5771

58-
> Скала сначала будет искать неявные параметры, доступ к которым можно получить напрямую (без префикса) в месте вызова метода в котором запрошены неявные параметры.
72+
object Comparator:
73+
given Comparator[Int] with
74+
def compare(x: Int, y: Int): Int = Integer.compare(x, y)
5975

60-
`intMonoid` - это задание неявного значения, доступ к которому можно получить непосредственно в `main`. Оно имеет подходящий тип, поэтому передается методу `sum` автоматически.
76+
given Comparator[String] with
77+
def compare(x: String, y: String): Int = x.compareTo(y)
78+
end Comparator
6179

62-
Второй вызов `sum` проходит используя `List[String]`, что означает, что `A` - это `String`. Неявный поиск будет идти так же, как и в случае с `Int`, но на этот раз будет найден `stringMonoid`, и передан автоматически в качестве `m`.
80+
def max[A](x: A, y: A)(using comparator: Comparator[A]): A =
81+
if comparator.compare(x, y) >= 0 then x
82+
else y
6383

64-
Программа выведет на экран
84+
println(max(10, 6)) // 10
85+
println(max("hello", "world")) // world
6586
```
66-
6
67-
abc
87+
88+
```scala
89+
// не компилируется:
90+
println(max(false, true))
91+
-- Error: ----------------------------------------------------------------------
92+
1 |println(max(false, true))
93+
| ^
94+
|no given instance of type Comparator[Boolean] was found for parameter comparator of method max
6895
```
96+
97+
Параметр `comparator` автоматически заполняется значением `given Comparator[Int]` для `max(10, 6)`
98+
и `given Comparator[String]` для `max("hello", "world")`.
99+
Поскольку нельзя найти `given Comparator[Boolean]`, вызов `max(false, true)` не компилируется.
100+
101+
{% endtab %}
102+
103+
{% endtabs %}
104+
105+
Места, где Scala будет искать эти параметры, делятся на две категории:
106+
107+
- Вначале Scala будет искать `given` параметры, доступ к которым можно получить напрямую (без префикса) в месте вызова `max`.
108+
- Затем он ищет членов, помеченных как given/implicit во всех объектах компаньонах,
109+
связанных с типом неявного параметра (например: `object Comparator` для типа-кандидата `Comparator[Int]`).
110+
111+
Более подробное руководство, о том где scala ищет неявные значения можно найти в [FAQ](/tutorials/FAQ/finding-implicits.html)

0 commit comments

Comments
 (0)