Skip to content

Commit 7e5b463

Browse files
Add types-intersection.md and types-union.md in ru (#2834)
1 parent 00c6026 commit 7e5b463

File tree

5 files changed

+190
-3
lines changed

5 files changed

+190
-3
lines changed

_overviews/scala3-book/types-intersection.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Intersection Types
33
type: section
44
description: This section introduces and demonstrates intersection types in Scala 3.
5-
languages: [zh-cn]
5+
languages: [ru, zh-cn]
66
num: 50
77
previous-page: types-generics
88
next-page: types-union

_overviews/scala3-book/types-union.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Union Types
33
type: section
44
description: This section introduces and demonstrates union types in Scala 3.
5-
languages: [zh-cn]
5+
languages: [ru, zh-cn]
66
num: 51
77
previous-page: types-intersection
88
next-page: types-adts-gadts

_ru/scala3/book/types-generics.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: 49
1111
previous-page: types-inferred
12-
next-page:
12+
next-page: types-intersection
1313
---
1414

1515
Универсальные (_generic_) классы (или trait-ы) принимают тип в качестве _параметра_ в квадратных скобках `[...]`.

_ru/scala3/book/types-intersection.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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: 50
11+
previous-page: types-generics
12+
next-page: types-union
13+
---
14+
15+
<span class="tag tag-inline">Только в Scala 3</span>
16+
17+
Используемый для типов оператор `&` создает так называемый _тип пересечения_ (_intersection type_).
18+
Тип `A & B` представляет собой значения, которые **одновременно** относятся как к типу `A`, так и к типу `B`.
19+
Например, в следующем примере используется тип пересечения `Resettable & Growable[String]`:
20+
21+
{% tabs intersection-reset-grow %}
22+
23+
{% tab 'Только в Scala 3' %}
24+
25+
```scala
26+
trait Resettable:
27+
def reset(): Unit
28+
29+
trait Growable[A]:
30+
def add(a: A): Unit
31+
32+
def f(x: Resettable & Growable[String]): Unit =
33+
x.reset()
34+
x.add("first")
35+
```
36+
37+
{% endtab %}
38+
39+
{% endtabs %}
40+
41+
В методе `f` в этом примере параметр `x` должен быть _одновременно_ как `Resettable`, так и `Growable[String]`.
42+
43+
Все _члены_ типа пересечения `A & B` являются типом `A` и типом `B`.
44+
Следовательно, как показано, для `Resettable & Growable[String]` доступны методы `reset` и `add`.
45+
46+
Пересечение типов может быть полезно для _структурного_ описания требований.
47+
В примере выше для `f` мы прямо заявляем, что нас устраивает любое значение для `x`,
48+
если оно является подтипом как `Resettable`, так и `Growable`.
49+
**Нет** необходимости создавать _номинальный_ вспомогательный trait, подобный следующему:
50+
51+
{% tabs normal-trait class=tabs-scala-version %}
52+
{% tab 'Scala 2' %}
53+
54+
```scala
55+
trait Both[A] extends Resettable with Growable[A]
56+
def f(x: Both[String]): Unit
57+
```
58+
59+
{% endtab %}
60+
61+
{% tab 'Scala 3' %}
62+
63+
```scala
64+
trait Both[A] extends Resettable, Growable[A]
65+
def f(x: Both[String]): Unit
66+
```
67+
68+
{% endtab %}
69+
{% endtabs %}
70+
71+
Существует важное различие между двумя вариантами определения `f`:
72+
в то время как оба позволяют вызывать `f` с экземплярами `Both`,
73+
только первый позволяет передавать экземпляры,
74+
которые являются подтипами `Resettable` и `Growable[String]`, _но не_ `Both[String]`.
75+
76+
> Обратите внимание, что `&` _коммутативно_: `A & B` имеет тот же тип, что и `B & A`.

_ru/scala3/book/types-union.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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: 51
11+
previous-page: types-intersection
12+
next-page:
13+
---
14+
15+
<span class="tag tag-inline">Только в Scala 3</span>
16+
17+
Используемый для типов `|` оператор создает так называемый _тип объединения_ (_union type_).
18+
Тип `А | B` представляет значения, которые относятся **либо** к типу `A`, **либо** к типу `B`.
19+
20+
В следующем примере метод `help` принимает параметр с именем `id` типа объединения `Username | Password`,
21+
который может быть либо `Username`, либо `Password`:
22+
23+
```scala
24+
case class Username(name: String)
25+
case class Password(hash: Hash)
26+
27+
def help(id: Username | Password) =
28+
val user = id match
29+
case Username(name) => lookupName(name)
30+
case Password(hash) => lookupPassword(hash)
31+
// дальнейший код ...
32+
```
33+
34+
Мы реализуем метод `help`, разделяя две альтернативы с использованием сопоставления с образцом.
35+
36+
Этот код является гибким и типобезопасным решением.
37+
Если попытаться передать тип, отличный от `Username` или `Password`, компилятор пометит это как ошибку:
38+
39+
```scala
40+
help("hi") // error: Found: ("hi" : String)
41+
// Required: Username | Password
42+
```
43+
44+
Ошибка также будет получена, если попытаться добавить `case` в выражение `match`,
45+
которое не соответствует типам `Username` или `Password`:
46+
47+
```scala
48+
case 1.0 => ??? // Ошибка: это строка не компилируется
49+
```
50+
51+
### Альтернатива объединенным типам
52+
53+
Как показано, объединенные типы могут использоваться для представления вариантов нескольких разных типов,
54+
не требуя, чтобы эти типы были частью специально созданной иерархии классов.
55+
56+
#### Предварительное планирование иерархии классов
57+
58+
Другие языки требуют предварительного планирования иерархии классов, как показано в следующем примере:
59+
60+
```scala
61+
trait UsernameOrPassword
62+
case class Username(name: String) extends UsernameOrPassword
63+
case class Password(hash: Hash) extends UsernameOrPassword
64+
def help(id: UsernameOrPassword) = ...
65+
```
66+
67+
Предварительное планирование не очень хорошо масштабируется,
68+
поскольку, например, требования пользователей API могут быть непредсказуемыми.
69+
Кроме того, загромождение иерархии типов маркерами типа `UsernameOrPassword` затрудняет чтение кода.
70+
71+
#### Теговые объединения
72+
73+
Другой альтернативой является задание отдельного типа перечисления, например:
74+
75+
```scala
76+
enum UsernameOrPassword:
77+
case IsUsername(u: Username)
78+
case IsPassword(p: Password)
79+
```
80+
81+
Перечисление `UsernameOrPassword` представляет собой _помеченное_ (_tagged_) объединение `Username` и `Password`.
82+
Однако этот способ моделирования объединения требует _явной упаковки и распаковки_,
83+
и, например, `Username` **не** является подтипом `UsernameOrPassword`.
84+
85+
### Вывод типов объединения
86+
87+
Компилятор присваивает типу объединения выражение, _только если_ такой тип явно задан.
88+
Например, рассмотрим такие значения:
89+
90+
```scala
91+
val name = Username("Eve") // name: Username = Username(Eve)
92+
val password = Password(123) // password: Password = Password(123)
93+
```
94+
95+
В этом REPL примере показано,
96+
как можно использовать тип объединения при привязке переменной к результату выражения `if`/`else`:
97+
98+
```
99+
scala> val a = if true then name else password
100+
val a: Object = Username(Eve)
101+
102+
scala> val b: Password | Username = if true then name else password
103+
val b: Password | Username = Username(Eve)
104+
```
105+
106+
Типом `a` является `Object`, который является супертипом `Username` и `Password`,
107+
но не _наименьшим_ супертипом, `Password | Username`.
108+
Если необходим наименьший супертип, его нужно указать явно, как это делается для `b`.
109+
110+
> Типы объединения являются двойственными типам пересечения.
111+
> И как `&` с типами пересечения, `|` также коммутативен: `A | B` того же типа, что и `B | А`.

0 commit comments

Comments
 (0)