Skip to content

Update generic-classes.md in russian #2856

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

Merged
merged 2 commits into from
Jul 10, 2023
Merged
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
79 changes: 74 additions & 5 deletions _ru/tour/generic-classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@ next-page: variances
previous-page: for-comprehensions
assumed-knowledge: classes unified-types
---

Обобщенные классы (Generic classes) - это классы, обладающие параметрическим полиморфизмом (т. е. классы, которые изменяют свое поведение в зависимости от приписываемого им типа. Этот тип указывается в квадратных скобках `[]` сразу после имени класса). Они особенно полезны для создания коллекций.

## Объявление обобщенного класса

Для объявления обобщенного класса необходимо после имени добавить тип в квадратных скобках `[]` как еще один параметр класса. По соглашению обычно используют заглавные буквы `A`, хотя можно использовать любые имена.

{% tabs generic-classes-1 class=tabs-scala-version %}
{% tab 'Scala 2' for=generic-classes-1 %}

```scala mdoc
class Stack[A] {
private var elements: List[A] = Nil
Expand All @@ -25,20 +31,64 @@ class Stack[A] {
}
}
```
Данная реализация класса `Stack` принимает в качестве параметра любой тип `A`. Это означает что список, `var elements: List[A] = Nil`, может хранить только элементы типа `A`. Процедура `def push` принимает только объекты типа `A` (примечание: `elements = x :: elements` переназначает `elements` в новый список, созданный путем добавления `x`а к текущим `elements`).

{% endtab %}
{% tab 'Scala 3' for=generic-classes-1 %}

```scala
class Stack[A]:
private var elements: List[A] = Nil
def push(x: A): Unit =
elements = x :: elements
def peek: A = elements.head
def pop(): A =
val currentTop = peek
elements = elements.tail
currentTop
```

{% endtab %}
{% endtabs %}

Данная реализация класса `Stack` принимает в качестве параметра любой тип `A`. Это означает что список, `var elements: List[A] = Nil`, может хранить только элементы типа `A`. Процедура `def push` принимает только объекты типа `A` (примечание: `elements = x :: elements` переназначает `elements` в новый список, созданный путем добавления `x` к текущим `elements`).

Здесь `Nil` — это пустой `List`, и его не следует путать с `null`.

## Использование

Чтобы использовать обобщенный класс, поместите конкретный тип в квадратные скобки вместо `A`.
```

{% tabs generic-classes-2 class=tabs-scala-version %}
{% tab 'Scala 2' for=generic-classes-2 %}

```scala mdoc
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop) // выведет 2
println(stack.pop) // выведет 1
println(stack.pop()) // выведет 2
println(stack.pop()) // выведет 1
```
Экземпляр `stack` может принимать только Intы. Однако, если тип имеет подтипы, то они также могут быть приняты:

{% endtab %}
{% tab 'Scala 3' for=generic-classes-2 %}

```scala
val stack = Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop()) // выведет 2
println(stack.pop()) // выведет 1
```

{% endtab %}
{% endtabs %}

Экземпляр `stack` может принимать элементы типа `Int`. Однако, если тип имеет подтипы, то они также могут быть приняты:

{% tabs generic-classes-3 class=tabs-scala-version %}
{% tab 'Scala 2' for=generic-classes-3 %}

```scala mdoc:nest
class Fruit
class Apple extends Fruit
class Banana extends Fruit
Expand All @@ -50,6 +100,25 @@ val banana = new Banana
stack.push(apple)
stack.push(banana)
```

{% endtab %}
{% tab 'Scala 3' for=generic-classes-3 %}

```scala
class Fruit
class Apple extends Fruit
class Banana extends Fruit

val stack = Stack[Fruit]
val apple = Apple()
val banana = Banana()

stack.push(apple)
stack.push(banana)
```

{% endtab %}
{% endtabs %}
Классы `Apple` и `Banana` наследуются от `Fruit` так, что мы можем засунуть экземпляры `Apple` и `Banana` в пачку `Fruit`.

_Примечание: подтипы обобщенных типов - *инвариантны*. Это означает, что если у нас есть стэк символов типа `Stack[Char]`, то он не может быть использован как стек интов типа `Stack[Int]`. Это нежелательное поведение, потому как позволило бы нам добавлять в стек символов целые числа. В заключение, `Stack[A]` является подтипом `Stack[B]` тогда и только тогда, когда `B = A`. Поскольку это может быть довольно строгим ограничением, Scala предлагает [механизм вариативного описания параметров типа](variances.html) для контроля за поведением подтипов._