diff --git a/_ru/tour/package-objects.md b/_ru/tour/package-objects.md index e7924e8de8..89c392ea46 100644 --- a/_ru/tour/package-objects.md +++ b/_ru/tour/package-objects.md @@ -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 @@ -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 @@ -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) { @@ -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 %} diff --git a/_ru/tour/packages-and-imports.md b/_ru/tour/packages-and-imports.md index a4d6710454..4624fa7238 100644 --- a/_ru/tour/packages-and-imports.md +++ b/_ru/tour/packages-and-imports.md @@ -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 @@ -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 @@ -44,18 +61,47 @@ 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 @@ -63,20 +109,65 @@ import users.{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` импортируются по умолчанию. diff --git a/_ru/tour/pattern-matching.md b/_ru/tour/pattern-matching.md index 91c6cf0867..e8e75e2ba3 100644 --- a/_ru/tour/pattern-matching.md +++ b/_ru/tour/pattern-matching.md @@ -49,7 +49,7 @@ x match {% endtab %} {% endtabs %} -Значение константы `x` выше представляет собой случайное целое число от 0 до 10. `x` становится левым операндом оператора `match`, а справа - выражением с четырьмя примерами (называемые еще _вариантами_). Последний вариант `_` - позволяет "поймать все оставшиеся варианты" т. е. для любого числа больше 2. +Значение константы `x` выше представляет собой случайное целое число от 0 до 9. `x` становится левым операндом оператора `match`, а справа - выражением с четырьмя примерами (называемые еще _вариантами_). Последний вариант `_` - позволяет "поймать все оставшиеся варианты" т. е. для любого числа больше 2. Сопоставление с примером возвращает значение.