Skip to content

Commit

Permalink
Tour packages actualization in ru (#2886)
Browse files Browse the repository at this point in the history
  • Loading branch information
artemkorsakov authored Sep 19, 2023
1 parent 9def5fa commit 41a18fe
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 14 deletions.
119 changes: 111 additions & 8 deletions _ru/tour/package-objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,47 @@ language: ru
previous-page: packages-and-imports
---

# Объекты Пакета
Часто бывает удобно иметь определения, доступные для всего пакета,
когда не нужно придумывать имя для оболочки `object`, которая их содержит.

У каждого пакета может существовать связанный с этим пакетом объект (package object), общий для всех членов пакета. Такой объект может быть только один. Любые выражения, содержащиеся в объекте пакета, считаются членами самого пакета.
{% tabs pkg-obj-vs-top-lvl_1 class=tabs-scala-version %}
{% tab 'Scala 2' for=pkg-obj-vs-top-lvl_1 %}

Объекты пакета могут содержать произвольные виды выражений, а не только переменные и методы. Например, они часто используются для хранения псевдонимов типа и наборов неявных преобразований доступных всему пакету. Объекты пакета могут также наследоваться от классов и трейтов Scala.
Scala 2 предоставляет _объекты пакета_ (_package objects_) в виде удобного контейнера, общего для всего пакета.

Объекты пакета могут содержать произвольные виды выражений, а не только переменные и методы.
Например, они часто используются для хранения псевдонимов типа и наборов неявных преобразований доступных всему пакету.
Объекты пакета могут также наследоваться от классов и трейтов Scala.

> В будущей версии Scala 3 объекты пакета будут удалены в пользу определений верхнего уровня.
По соглашению, исходный код объекта пакета обычно помещается в файл под названием `package.scala`.

Каждому пакету разрешено иметь один объект пакета.
Любые выражения, содержащиеся в объекте пакета, считаются членами самого пакета.

{% endtab %}
{% tab 'Scala 3' for=pkg-obj-vs-top-lvl_1 %}

В Scala 3 любое определение может быть объявлено на верхнем уровне пакета.
Например, классы, перечисления, методы и переменные.

Любые определения, размещенные на верхнем уровне пакета, считаются членами самого пакета.

> В Scala 2 верхнеуровневый метод, определения типов и переменных должны были быть заключены в **объект пакета**.
> Их все еще можно использовать в Scala 3 для обратной совместимости.
> Вы можете увидеть, как они работают, переключая вкладки.
{% endtab %}
{% endtabs %}

См. пример ниже. Предположим, есть старший класс `Fruit` и три наследуемых от него объекта `Fruit` в пакете.

`gardening.fruits`:

{% tabs pkg-obj-vs-top-lvl_2 %}
{% tab 'Scala 2 и 3' for=pkg-obj-vs-top-lvl_2 %}

```
// в файле gardening/fruits/Fruit.scala
package gardening.fruits
Expand All @@ -29,9 +58,15 @@ object Plum extends Fruit("Plum", "blue")
object Banana extends Fruit("Banana", "yellow")
```

{% endtab %}
{% endtabs %}

Теперь предположим, что мы хотим поместить переменную `planted` и метод `showFruit` непосредственно в пакет `gardening`.
Вот как это делается:

{% tabs pkg-obj-vs-top-lvl_3 class=tabs-scala-version %}
{% tab 'Scala 2' for=pkg-obj-vs-top-lvl_3 %}

```
// в файле gardening/fruits/package.scala
package gardening
Expand All @@ -43,11 +78,31 @@ package object fruits {
}
```

Для примера, следующий объект `PrintPlanted` импортирует `planted` и `showFruit` точно так же, как с вариантом импорта класса `Fruit`, используя групповой стиль импорта пакета gardening.fruits:
{% endtab %}
{% tab 'Scala 3' for=pkg-obj-vs-top-lvl_3 %}

```
// в файле gardening/fruits/package.scala
package gardening.fruits
val planted = List(Apple, Plum, Banana)
def showFruit(fruit: Fruit): Unit =
println(s"${fruit.name}s are ${fruit.color}")
```

{% endtab %}
{% endtabs %}

Для примера, следующий объект `PrintPlanted` импортирует `planted` и `showFruit` точно так же, как с вариантом импорта класса `Fruit`,
используя групповой стиль импорта пакета `gardening.fruits`:

{% tabs pkg-obj-vs-top-lvl_4 class=tabs-scala-version %}
{% tab 'Scala 2' for=pkg-obj-vs-top-lvl_4 %}

```
// в файле PrintPlanted.scala
import gardening.fruits._
object PrintPlanted {
def main(args: Array[String]): Unit = {
for (fruit <- planted) {
Expand All @@ -57,10 +112,58 @@ object PrintPlanted {
}
```

Объекты пакета ведут себя также, как и любые другие объекты. Это означает, что вы можете использовать наследование, при этом сразу нескольких трейтов:
{% endtab %}
{% tab 'Scala 3' for=pkg-obj-vs-top-lvl_4 %}

```
package object fruits extends FruitAliases with FruitHelpers {
// здесь располагаются вспомогательные классы и переменные
}
// в файле PrintPlanted.scala
import gardening.fruits.*
@main def printPlanted(): Unit =
for fruit <- planted do
showFruit(fruit)
```

{% endtab %}
{% endtabs %}

### Объединение нескольких определений на уровне пакета

Часто в вашем проекте может быть несколько повторно используемых определений,
заданных в различных модулях, которые вы хотите агрегировать на верхнем уровне пакета.

Например, некоторые вспомогательные методы в трейте `FruitHelpers`
и некоторые псевдонимы терминов/типов в свойстве `FruitAliases`.
Вот как вы можете разместить все их определения на уровне пакета `fruit`:

{% tabs pkg-obj-vs-top-lvl_5 class=tabs-scala-version %}
{% tab 'Scala 2' for=pkg-obj-vs-top-lvl_5 %}

Объекты пакета ведут себя также, как и любые другие объекты.
Это означает, что вы можете использовать наследование, при этом сразу нескольких трейтов:

```
package gardening
// `fruits` наследует свои элементы от родителей.
package object fruits extends FruitAliases with FruitHelpers
```

{% endtab %}
{% tab 'Scala 3' for=pkg-obj-vs-top-lvl_5 %}

В Scala 3 предпочтительно использовать `export` для объединения членов из нескольких объектов в единую область видимости.
Здесь мы определяем приватные объекты, которые смешиваются с вспомогательными трейтами,
а затем экспортируют их элементы на верхнем уровне:

```
package gardening.fruits
private object FruitAliases extends FruitAliases
private object FruitHelpers extends FruitHelpers
export FruitHelpers.*, FruitAliases.*
```

{% endtab %}
{% endtabs %}
101 changes: 96 additions & 5 deletions _ru/tour/packages-and-imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,28 @@ previous-page: annotations
next-page: package-objects
---

# Пакеты и Импорт
# Пакеты и Импорт

Scala использует пакеты для указания пространства имен, они позволяют создавать модульную структуру кода.

## Создание пакета

Пакеты создаются путем объявления одного или нескольких имен пакетов в верхней части файла Scala.

{% tabs packages-and-imports_1 %}
{% tab 'Scala 2 и 3' for=packages-and-imports_1 %}

```
package users
class User
```

{% endtab %}
{% endtabs %}

По соглашению пакеты называют тем же именем, что и каталог, содержащий файл Scala. Однако Scala не обращает внимания на расположение файлов. Структура каталогов sbt-проекта для `package users` может выглядеть следующим образом:

```
- ExampleProject
- build.sbt
Expand All @@ -33,8 +43,15 @@ class User
UserPreferences.scala
- test
```
Обратите внимание, что каталог `users` находится внутри каталога `scala` и как в пакете содержатся несколько файлов Scala. Каждый файл Scala в пакете может иметь одно и то же объявление пакета. Другой способ объявления пакетов - с помощью фигурных скобок:
```

Обратите внимание, что каталог `users` находится внутри каталога `scala` и как в пакете содержатся несколько файлов Scala.
Каждый файл Scala в пакете может иметь одно и то же объявление пакета.
Другой способ объявления пакетов - вложить их друг в друга::

{% tabs packages-and-imports_2 class=tabs-scala-version %}
{% tab 'Scala 2' for=packages-and-imports_2 %}

```scala
package users {
package administrators {
class NormalUser
Expand All @@ -44,39 +61,113 @@ package users {
}
}
```

{% endtab %}
{% tab 'Scala 3' for=packages-and-imports_2 %}

```scala
package users:
package administrators:
class NormalUser

package normalusers:
class NormalUser
```

{% endtab %}
{% endtabs %}

Как видите, такой способ позволяет вкладывать пакеты друг в друга, а также обеспечивает отличный контроль за областью видимости и возможностью изоляции.

Имя пакета должно быть все в нижнем регистре, и если код разрабатывается в организации имеющей сайт, то следует использовать имя следующего формата: `<домен-верхнего-уровня>.<доменное-имя>.<название-проекта>`. Например, если бы у Google был проект под названием `SelfDrivingCar`, название пакета выглядело бы следующим образом:
```

{% tabs packages-and-imports_3 %}
{% tab 'Scala 2 и 3' for=packages-and-imports_3 %}

```scala
package com.google.selfdrivingcar.camera

class Lens
```

{% endtab %}
{% endtabs %}

Что может соответствовать следующей структуре каталога: `SelfDrivingCar/src/main/scala/com/google/selfdrivingcar/camera/Lens.scala`.

## Импорт

Указание `import` открывает доступ к членам (классам, трейтам, функциям и т.д.) в других пакетах. Указание `import` не требуется для доступа к членам одного и того же пакета. Указание `import` избирательны:

{% tabs packages-and-imports_4 class=tabs-scala-version %}
{% tab 'Scala 2' for=packages-and-imports_4 %}

```
import users._ // групповой импорт всего пакета users
import users.User // импортировать только User
import users.{User, UserPreferences} // импортировать только User, UserPreferences
import users.{UserPreferences => UPrefs} // импортировать и переименовать
```

{% endtab %}
{% tab 'Scala 3' for=packages-and-imports_4 %}

```
import users.* // групповой импорт всего пакета users, кроме given
import users.given // импорт всех given пакета users
import users.User // импортировать только User
import users.{User, UserPreferences} // импортировать только User, UserPreferences
import users.UserPreferences as UPrefs // импортировать и переименовать
```

{% endtab %}
{% endtabs %}

Одним из отличий Scala от Java является то, что импорт можно использовать где угодно:

{% tabs packages-and-imports_5 class=tabs-scala-version %}
{% tab 'Scala 2' for=packages-and-imports_5 %}

```scala mdoc
def sqrtplus1(x: Int) = {
import scala.math.sqrt
sqrt(x) + 1.0
}
```
В случае возникновения конфликта имен и необходимости импортировать что-либо из корня проекта, имя пакета должно начинаться с префикса `_root_`:

{% endtab %}
{% tab 'Scala 3' for=packages-and-imports_5 %}

```scala
def sqrtplus1(x: Int) =
import scala.math.sqrt
sqrt(x) + 1.0
```

{% endtab %}
{% endtabs %}

В случае возникновения конфликта имен и необходимости импортировать что-либо из корня проекта, имя пакета должно начинаться с префикса `_root_`:

{% tabs packages-and-imports_6 class=tabs-scala-version %}
{% tab 'Scala 2' for=packages-and-imports_6 %}

```scala
package accounts

import _root_.users._
```

{% endtab %}
{% tab 'Scala 3' for=packages-and-imports_6 %}

```scala
package accounts

import _root_.users.*
```

{% endtab %}
{% endtabs %}

Примечание: Пакеты `scala` и `java.lang`, а также `object Predef` импортируются по умолчанию.
2 changes: 1 addition & 1 deletion _ru/tour/pattern-matching.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ x match
{% endtab %}
{% endtabs %}

Значение константы `x` выше представляет собой случайное целое число от 0 до 10. `x` становится левым операндом оператора `match`, а справа - выражением с четырьмя примерами (называемые еще _вариантами_). Последний вариант `_` - позволяет "поймать все оставшиеся варианты" т. е. для любого числа больше 2.
Значение константы `x` выше представляет собой случайное целое число от 0 до 9. `x` становится левым операндом оператора `match`, а справа - выражением с четырьмя примерами (называемые еще _вариантами_). Последний вариант `_` - позволяет "поймать все оставшиеся варианты" т. е. для любого числа больше 2.

Сопоставление с примером возвращает значение.

Expand Down

0 comments on commit 41a18fe

Please sign in to comment.