From 8647ee5f22c8e54fefba6222e7ad477ed62c8b6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D0=BE=D1=80=D1=81?= =?UTF-8?q?=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sat, 15 Jul 2023 10:50:04 +0300 Subject: [PATCH 1/3] Update compound-types.md in russian --- _ru/tour/compound-types.md | 71 +++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/_ru/tour/compound-types.md b/_ru/tour/compound-types.md index 5d0a49aa0e..876bbaf42a 100644 --- a/_ru/tour/compound-types.md +++ b/_ru/tour/compound-types.md @@ -8,13 +8,19 @@ next-page: self-types previous-page: abstract-type-members --- -Иногда необходимо выразить, то что тип объекта является подтипом нескольких других типов. В Scala это можно выразить с помощью *составных типов*, которые являются объединением нескольких типов объектов. +Иногда необходимо выразить, то что тип объекта является подтипом нескольких других типов. + +В Scala это можно выразить с помощью _типов пересечений_ (или _составных типов_ в Scala 2), +которые являются объединением нескольких типов объектов. Предположим, у нас есть два трейта: `Cloneable` и `Resetable`: +{% tabs compound-types_1 class=tabs-scala-version %} +{% tab 'Scala 2' for=compound-types_1 %} + ```scala mdoc trait Cloneable extends java.lang.Cloneable { - override def clone(): Cloneable = { + override def clone(): Cloneable = { // создает публичный метод 'clone' super.clone().asInstanceOf[Cloneable] } } @@ -23,9 +29,26 @@ trait Resetable { } ``` -Теперь предположим, что мы хотим написать функцию `cloneAndReset`, которая берет объект, клонирует его и сбрасывает (Reset) состояние исходного объекта: +{% endtab %} +{% tab 'Scala 3' for=compound-types_1 %} +```scala +trait Cloneable extends java.lang.Cloneable: + override def clone(): Cloneable = // создает публичный метод 'clone' + super.clone().asInstanceOf[Cloneable] +trait Resetable: + def reset: Unit ``` + +{% endtab %} +{% endtabs %} + +Теперь предположим, что мы хотим написать функцию `cloneAndReset`, которая берет объект, клонирует его и сбрасывает (Reset) состояние исходного объекта: + +{% tabs compound-types_2 class=tabs-scala-version %} +{% tab 'Scala 2' for=compound-types_2 %} + +```scala mdoc:fail def cloneAndReset(obj: ?): Cloneable = { val cloned = obj.clone() obj.reset @@ -33,17 +56,49 @@ def cloneAndReset(obj: ?): Cloneable = { } ``` -Возникает вопрос, какой тип параметр `obj` должна принимать наша объединённая функция. Если это `Cloneable`, то объект может использовать метод `clone`, но не `reset`; если это `Resetable` мы можем использовать метод `reset`, но нет операции `clone`. Чтобы избежать приведения типа в такой ситуации, мы можем указать, что тип `obj` является и `Cloneable`, и `Resetable`. Этот совместный тип в Scala записывается как: `Cloneable with Resetable`. +{% endtab %} +{% tab 'Scala 3' for=compound-types_2 %} + +```scala +def cloneAndReset(obj: ?): Cloneable = + val cloned = obj.clone() + obj.reset + cloned +``` + +{% endtab %} +{% endtabs %} + +Возникает вопрос, какой тип параметра `obj` должна принимать наша объединённая функция. Если это `Cloneable`, то объект может использовать метод `clone`, но не `reset`; если это `Resetable` мы можем использовать метод `reset`, но нет операции `clone`. Чтобы избежать приведения типа в такой ситуации, мы можем указать, что тип `obj` является и `Cloneable`, и `Resetable`. + +{% tabs compound-types_3 class=tabs-scala-version %} +{% tab 'Scala 2' for=compound-types_3 %} +Этот совместный тип в Scala записывается как: `Cloneable with Resetable`. Вот обновленная функция: -``` +```scala mdoc:fail def cloneAndReset(obj: Cloneable with Resetable): Cloneable = { //... } ``` -Составные типы могут состоять из нескольких типов объектов, и они могут содержать единый доработанный объект, в котором будут доработаны характеристики существующих членов объекта. -Общая форма записи: `A with B with C ... { доработанный объект }` +Обратите внимание, что у вас может быть более двух типов: `A with B with C with ...`. +Это означает то же самое, что и: `(...(A with B) with C) with ... )` + +{% endtab %} +{% tab 'Scala 3' for=compound-types_3 %} +Этот совместный тип в Scala записывается как: `Cloneable & Resetable`. + +Вот обновленная функция: + +```scala +def cloneAndReset(obj: Cloneable & Resetable): Cloneable = { + //... +} +``` -Пример использования таких доработок приведен на странице об [объединении классов с примесями](mixin-class-composition.html). +Обратите внимание, что у вас может быть более двух типов: `A & B & C & ...`. +`&` является ассоциативным, поэтому скобки могут быть добавлены вокруг любой части без изменения значения. +{% endtab %} +{% endtabs %} From 078a296f7fe4cee79c028d199119206733d2e645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D0=BE=D1=80=D1=81?= =?UTF-8?q?=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Tue, 15 Aug 2023 08:51:12 +0300 Subject: [PATCH 2/3] Update package-objects.md and packages-and-imports.md in russian --- _ru/tour/package-objects.md | 119 ++++++++++++++++++++++++++++--- _ru/tour/packages-and-imports.md | 101 ++++++++++++++++++++++++-- 2 files changed, 207 insertions(+), 13 deletions(-) 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` импортируются по умолчанию. From 04e80ea769737a09f34186fac8262774a8fd053c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D0=BE=D1=80=D1=81?= =?UTF-8?q?=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Tue, 15 Aug 2023 08:56:45 +0300 Subject: [PATCH 3/3] Update package-objects.md and packages-and-imports.md in russian --- _ru/tour/pattern-matching.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. Сопоставление с примером возвращает значение.