Skip to content
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

Update inner-classes.md in russian #2869

Merged
merged 1 commit into from
Jul 17, 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
65 changes: 64 additions & 1 deletion _ru/tour/inner-classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ previous-page: lower-type-bounds

Чтобы проиллюстрировать суть подхода, мы быстро набросаем реализацию такого графа:

{% tabs inner-classes_1 class=tabs-scala-version %}
{% tab 'Scala 2' for=inner-classes_1 %}

```scala mdoc
class Graph {
class Node {
Expand All @@ -30,8 +33,33 @@ class Graph {
}
}
```

{% endtab %}
{% tab 'Scala 3' for=inner-classes_1 %}

```scala
class Graph:
class Node:
var connectedNodes: List[Node] = Nil
def connectTo(node: Node): Unit =
if !connectedNodes.exists(node.equals) then
connectedNodes = node :: connectedNodes

var nodes: List[Node] = Nil
def newNode: Node =
val res = Node()
nodes = res :: nodes
res
```

{% endtab %}
{% endtabs %}

Данная программа представляет собой граф в составленного из списка узлов (`List[Node]`). Каждый узел имеет список других узлов, с которым он связан (`connectedNodes`). Класс `Node` является _зависимым от месторасположения типом_, поскольку он вложен в `Class Graph`. Поэтому все узлы в `connectedNodes` должны быть созданы с использованием `newNode` из одного и того же экземпляра `Graph`.

{% tabs inner-classes_2 %}
{% tab 'Scala 2 и 3' for=inner-classes_2 %}

```scala mdoc
val graph1: Graph = new Graph
val node1: graph1.Node = graph1.newNode
Expand All @@ -40,12 +68,19 @@ val node3: graph1.Node = graph1.newNode
node1.connectTo(node2)
node3.connectTo(node1)
```

{% endtab %}
{% endtabs %}

Мы явно объявили тип `node1`, `node2` и `node3` как `graph1.Node` для ясности, хотя компилятор мог определить это самостоятельно. Это потому, что когда мы вызываем `graph1.newNode`, вызывающий `new Node`, метод использует экземпляр `Node`, специфичный экземпляру `graph1`.

Если у нас есть два графа, то система типов Scala не позволит смешивать узлы, определенные в рамках одного графа, с узлами другого, так как узлы другого графа имеют другой тип.
Вот некорректная программа:

```scala:nest
{% tabs inner-classes_3 %}
{% tab 'Scala 2 и 3' for=inner-classes_3 %}

```scala mdoc:fail
val graph1: Graph = new Graph
val node1: graph1.Node = graph1.newNode
val node2: graph1.Node = graph1.newNode
Expand All @@ -54,8 +89,15 @@ val graph2: Graph = new Graph
val node3: graph2.Node = graph2.newNode
node1.connectTo(node3) // не работает!
```

{% endtab %}
{% endtabs %}

Тип `graph1.Node` отличается от типа `graph2.Node`. В Java последняя строка в предыдущем примере программы была бы правильной. Для узлов обоих графов Java будет присваивать один и тот же тип `Graph.Node`, т.е. `Node` имеет префикс класса `Graph`. В Скале такой тип также может быть выражен, он записывается `Graph#Node`. Если мы хотим иметь возможность соединять узлы разных графов, то вам нужно изменить описание первоначальной реализации графов следующим образом:

{% tabs inner-classes_4 class=tabs-scala-version %}
{% tab 'Scala 2' for=inner-classes_4 %}

```scala mdoc:nest
class Graph {
class Node {
Expand All @@ -74,3 +116,24 @@ class Graph {
}
}
```

{% endtab %}
{% tab 'Scala 3' for=inner-classes_4 %}

```scala
class Graph:
class Node:
var connectedNodes: List[Graph#Node] = Nil
def connectTo(node: Graph#Node): Unit =
if !connectedNodes.exists(node.equals) then
connectedNodes = node :: connectedNodes

var nodes: List[Node] = Nil
def newNode: Node =
val res = Node()
nodes = res :: nodes
res
```

{% endtab %}
{% endtabs %}
Loading