layout | title | scala3 | partof | overview-name | type | description | language | num | previous-page | next-page |
---|---|---|---|---|---|---|---|---|---|---|
multipage-overview |
Возможности Scala |
true |
scala3-book |
Scala 3 — Book |
chapter |
На этой странице рассматриваются основные возможности языка программирования Scala. |
ru |
2 |
introduction |
why-scala-3 |
Название Scala происходит от слова scalable, и в соответствии с этим названием язык Scala используется для поддержки загруженных веб-сайтов и анализа огромных наборов данных. В этом разделе представлены функции, которые делают Scala масштабируемым языком. Эти функции разделены на три раздела:
- Функции высокоуровневого языка программирования
- Функции низкоуровневого языка программирования
- Особенности экосистемы Scala
Глядя на Scala с пресловутого “вида с высоты 30 000 фунтов”, вы можете сделать о нем следующие утверждения:
- Это высокоуровневый язык программирования
- Он имеет краткий, читаемый синтаксис
- Он статически типизирован (но кажется динамичным)
- Имеет выразительную систему типов
- Это язык функционального программирования (ФП)
- Это язык объектно-ориентированного программирования (ООП)
- Он поддерживает слияние ФП и ООП
- Контекстные абстракции обеспечивают понятный способ реализации вывода терминов (term inference)
- Он работает на JVM (и в браузере)
- Беспрепятственно взаимодействует с Java кодом
- Он используется для серверных приложений (включая микросервисы), приложений для работы с большими данными, а также может использоваться в браузере с помощью Scala.js
Эти функции кратко рассматриваются в следующих разделах.
Scala считается высокоуровневым языком как минимум по двум причинам. Во-первых, подобно Java и многим другим современным языкам, вы не имеете дело с низкоуровневыми понятиями, такими как указатели и управление памятью.
Во-вторых, с использованием лямбда-выражений и функций высшего порядка вы пишете свой код на очень высоком уровне. Как говорится в функциональном программировании, в Scala вы пишете то, что хотите, а не то, как этого добиться. То есть мы не пишем императивный код вот так:
{% tabs scala-features-1 class=tabs-scala-version %} {% tab 'Scala 2' for=scala-features-1 %}
import scala.collection.mutable.ListBuffer
def double(ints: List[Int]): List[Int] = {
val buffer = new ListBuffer[Int]()
for (i <- ints) {
buffer += i * 2
}
buffer.toList
}
val oldNumbers = List(1, 2, 3)
val newNumbers = double(oldNumbers)
{% endtab %} {% tab 'Scala 3' for=scala-features-1 %}
import scala.collection.mutable.ListBuffer
def double(ints: List[Int]): List[Int] =
val buffer = new ListBuffer[Int]()
for i <- ints do
buffer += i * 2
buffer.toList
val oldNumbers = List(1, 2, 3)
val newNumbers = double(oldNumbers)
{% endtab %} {% endtabs %}
Этот код шаг за шагом указывает компилятору, что делать. Вместо этого мы пишем высокоуровневый функциональный код, используя функции высшего порядка и лямбда-выражения, подобные этому, для вычисления того же результата:
{% tabs scala-features-2 %} {% tab 'Scala 2 и 3' for=scala-features-2 %}
val newNumbers = oldNumbers.map(_ * 2)
{% endtab %} {% endtabs %}
Как видите, этот код намного лаконичнее, его легче читать и легче поддерживать.
Scala имеет краткий, удобочитаемый синтаксис. Например, переменные создаются лаконично, а их типы понятны:
{% tabs scala-features-3 %} {% tab 'Scala 2 и 3' for=scala-features-3 %}
val nums = List(1,2,3)
val p = Person("Martin", "Odersky")
{% endtab %} {% endtabs %}
Функции высшего порядка и лямбда-выражения делают код кратким и удобочитаемым:
{% tabs scala-features-4 %} {% tab 'Scala 2 и 3' for=scala-features-4 %}
nums.map(i => i * 2) // длинная форма
nums.map(_ * 2) // краткая форма
nums.filter(i => i > 1)
nums.filter(_ > 1)
{% endtab %} {% endtabs %}
Трэйты, классы и методы определяются с помощью простого и легкого синтаксиса:
{% tabs scala-features-5 class=tabs-scala-version %} {% tab 'Scala 2' for=scala-features-5 %}
trait Animal {
def speak(): Unit
}
trait HasTail {
def wagTail(): Unit
}
class Dog extends Animal with HasTail {
def speak(): Unit = println("Woof")
def wagTail(): Unit = println("⎞⎜⎛ ⎞⎜⎛")
}
{% endtab %} {% tab 'Scala 3' for=scala-features-5 %}
trait Animal:
def speak(): Unit
trait HasTail:
def wagTail(): Unit
class Dog extends Animal, HasTail:
def speak(): Unit = println("Woof")
def wagTail(): Unit = println("⎞⎜⎛ ⎞⎜⎛")
{% endtab %} {% endtabs %}
Исследования показали, что время, которое разработчик тратит на чтение и написание кода, составляет как минимум 10:1, поэтому важно писать краткий и читабельный код.
Scala — это язык со статической типизацией, но благодаря своим возможностям вывода типов он кажется динамичным. Все эти выражения выглядят как языки с динамической типизацией, такие как Python или Ruby, но это все Scala:
{% tabs scala-features-6 class=tabs-scala-version %} {% tab 'Scala 2' for=scala-features-6 %}
val s = "Hello"
val p = Person("Al", "Pacino")
val sum = nums.reduceLeft(_ + _)
val y = for (i <- nums) yield i * 2
val z = nums
.filter(_ > 100)
.filter(_ < 10_000)
.map(_ * 2)
{% endtab %} {% tab 'Scala 3' for=scala-features-6 %}
val s = "Hello"
val p = Person("Al", "Pacino")
val sum = nums.reduceLeft(_ + _)
val y = for i <- nums yield i * 2
val z = nums
.filter(_ > 100)
.filter(_ < 10_000)
.map(_ * 2)
{% endtab %} {% endtabs %}
Как утверждает Heather Miller, Scala считается сильным языком со статической типизацией, и вы получаете все преимущества статических типов:
- Корректность: вы обнаруживаете большинство ошибок во время компиляции
- Отличная поддержка IDE
- Надежное автодополнение кода
- Отлов ошибок во время компиляции означает отлов ошибок по мере написания
- Простой и надежный рефакторинг
- Вы можете уверенно рефакторить свой код
- Объявления типов методов сообщают читателям, что делает метод, и помогают служить документацией
- Масштабируемость и удобство обслуживания: типы помогают обеспечить корректность в произвольно больших приложениях и командах разработчиков
- Строгая типизация в сочетании с превосходным выводом типов позволяет использовать такие механизмы, как [контекстная абстракция]({{ site.scala3ref }}/contextual), которая позволяет вам опускать шаблонный код. Часто этот шаблонный код может быть выведен компилятором на основе определений типов и заданного контекста.
Система типов в Scala во время компиляции обеспечивает безопасное и согласованное использование абстракций. В частности, система типов поддерживает:
- [Выводимые типы]({% link _overviews/scala3-book/types-inferred.md %})
- [Generic классы]({% link _overviews/scala3-book/types-generics.md %})
- [Аннотации вариантности]({% link _overviews/scala3-book/types-variance.md %})
- Верхняя и нижняя границы типов
- Полиморфные методы
- [Типы пересечения]({% link _overviews/scala3-book/types-intersection.md %})
- [Типы объединения]({% link _overviews/scala3-book/types-union.md %})
- [Лямбда-типы]({{ site.scala3ref }}/new-types/type-lambdas.html)
- [Экземпляры
given
и предложенияusing
]({% link _overviews/scala3-book/ca-context-parameters.md %}) - [Методы расширения]({% link _overviews/scala3-book/ca-extension-methods.md %})
- [Типовые классы]({% link _overviews/scala3-book/ca-type-classes.md %})
- [Многостороннее равенство]({% link _overviews/scala3-book/ca-multiversal-equality.md %})
- [Псевдонимы непрозрачного типа]({% link _overviews/scala3-book/types-opaque-types.md %})
- [Открытые классы]({{ site.scala3ref }}/other-new-features/open-classes.html)
- [Типы соответствия]({{ site.scala3ref }}/new-types/match-types.html)
- [Зависимые типы функций]({{ site.scala3ref }}/new-types/dependent-function-types.html)
- [Полиморфные функциональные типы]({{ site.scala3ref }}/new-types/polymorphic-function-types.html)
- [Контекстные границы]({{ site.scala3ref }}/contextual/context-bounds.html)
- [Контекстные функции]({{ site.scala3ref }}/contextual/context-functions.html)
- Внутренние классы и элементы абстрактного типа как элементы объекта
В сочетании эти функции обеспечивают мощную основу для безопасного повторного использования программных абстракций и для безопасного расширения программного обеспечения.
Scala — это язык функционального программирования (ФП), что означает:
- Функции — это значения, и их можно передавать, как и любое другое значение
- Напрямую поддерживаются функции высшего порядка
- Встроенные лямбда
- Все в Scala — это выражение, возвращающее значение
- Синтаксически легко использовать неизменяемые переменные, и их использование приветствуется
- В стандартной библиотеке языка содержится множество неизменяемых классов коллекций
- Эти классы коллекций поставляются с десятками функциональных методов: они не изменяют коллекцию, вместо этого возвращая обновленную копию данных
Scala — это язык объектно-ориентированного программирования (ООП). Каждое значение — это экземпляр класса, а каждый “оператор” — это метод.
В Scala все типы наследуются от класса верхнего уровня Any
, чьими непосредственными дочерними элементами являются AnyVal
(типы значений, такие как Int
и Boolean
) и AnyRef
(ссылочные типы, как в Java).
Это означает, что различие в Java между примитивными и упакованными типами (например, int
против Integer
) отсутствует в Scala.
Упаковка и распаковка полностью прозрачны для пользователя.
Суть Scala заключается в слиянии функционального программирования и объектно-ориентированного программирования в типизированной среде:
- Функции для логики
- Объекты для модульности
Как заявил Мартин Одерски, “Scala был разработан, чтобы показать, что слияние функционального и объектно-ориентированного программирования возможно и практично”.
После Haskell Scala был вторым популярным языком, в котором была некоторая форма неявных (implicits) выражений. В Scala 3 эти концепции были полностью переосмыслены и реализованы более четко.
Основная идея заключается в выводе терминов: на основе заданного, компилятор синтезирует “канонический” термин, который имеет этот тип. В Scala параметр контекста напрямую ведет к выводимому термину аргумента, который также может быть записан явно.
Примеры использования этой концепции включают реализацию [типовых классов]({% link _overviews/scala3-book/ca-type-classes.md %}), установление контекста, внедрение зависимостей, выражение возможностей, вычисление новых типов и доказательство отношений между ними.
Scala 3 делает этот процесс более понятным, чем когда-либо прежде. О контекстных абстракциях можно прочесть в [Справочной документации]({{ site.scala3ref }}/contextual).
Код Scala работает на виртуальной машине Java (JVM), поэтому вы получаете все ее преимущества:
- Безопасность
- Производительность
- Управление памятью
- Портативность и независимость от платформы
- Возможность использовать множество существующих Java и JVM библиотек
Помимо работы на JVM, Scala также работает в браузере с помощью Scala.js (и сторонних инструментов с открытым исходным кодом для интеграции популярных библиотек JavaScript), а собственные исполняемые файлы могут быть созданы с помощью Scala Native и GraalVM.
Вы можете использовать Java классы и библиотеки в своих приложениях Scala, а также код Scala в приложениях Java. Что касается второго пункта, большие библиотеки, такие как Akka и Play Framework написаны на Scala и могут использоваться в приложениях Java.
Что касается первого пункта, классы и библиотеки Java используются в приложениях Scala каждый день.
Например, в Scala вы можете читать файлы с помощью BufferedReader
и FileReader
из Java:
{% tabs scala-features-7 %} {% tab 'Scala 2 и 3' for=scala-features-7 %}
import java.io.*
val br = BufferedReader(FileReader(filename))
// чтение файла в `br` ...
{% endtab %} {% endtabs %}
Использование Java-кода в Scala, как правило, не вызывает затруднений.
В Scala также можно использовать коллекции Java, и если вы хотите использовать с ними богатый набор методов классов коллекций Scala, то можете преобразовать их с помощью всего нескольких строк кода:
{% tabs scala-features-8 %} {% tab 'Scala 2 и 3' for=scala-features-8 %}
import scala.jdk.CollectionConverters.*
val scalaList: Seq[Integer] = JavaClass.getJavaList().asScala.toSeq
{% endtab %} {% endtabs %}
Как будет видно в третьем разделе этой страницы, библиотеки и фреймворки Scala, подобные нижеследующим, были написаны для поддержки загруженных веб-сайтов и работы с огромными наборами данных:
- Play Framework — это легкая, без сохранения состояния, удобная для web, удобная для разработчиков архитектура для создания масштабируемых приложений
- Apache Spark — это унифицированный аналитический механизм для обработки больших данных со встроенными модулями для потоковой передачи, SQL, машинного обучения и обработки графиков
В списке Awesome Scala представлены десятки дополнительных инструментов с открытым исходным кодом, созданных разработчиками для создания приложений Scala.
В дополнение к программированию на стороне сервера, Scala.js представляет собой строго типизированную замену для написания JavaScript со сторонними библиотеками с открытым исходным кодом, которые включают инструменты для интеграции с библиотекой Facebook React, jQuery и т.д.
Хотя в предыдущем разделе были рассмотрены высокоуровневые функции Scala, интересно отметить, что на высоком уровне вы можете делать одни и те же утверждения как о Scala 2, так и о Scala 3. Десять лет назад Scala начиналась с прочного фундамента желаемых функций, и вы увидите в этом разделе, что в Scala 3 эти преимущества были улучшены.
С точки зрения деталей “на уровне моря” — то есть функций языка, которые программисты используют каждый день — Scala 3 имеет значительные преимущества по сравнению со Scala 2:
- Возможность более лаконично создавать алгебраические типы данных (ADT) с перечислениями
- Еще более лаконичный и читаемый синтаксис:
- Синтаксис “тихой” структуры управления легче читать
- Опциональные фигурные скобки
- Меньшее количество символов в коде создает меньше визуального шума, что упрощает его чтение
- Ключевое слово
new
обычно больше не требуется при создании экземпляров класса - Формальность объектов пакета была заменена более простыми определениями “верхнего уровня”
- Более понятная грамматика:
- Несколько различных вариантов использования ключевого слова
implicit
были удалены; это использование заменено более очевидными ключевыми словами, такими какgiven
,using
, иextension
, фокусирующихся на намерении, а не механизме (подробности см. в разделе [Givens][givens]) - [Методы расширения][extension] заменяют неявные классы более понятным и простым механизмом
- Добавление модификатора
open
для классов заставляет разработчика намеренно объявить, что класс открыт для модификации, тем самым ограничивая специальные расширения кодовой базы - [Многостороннее равенство][multiversal] исключает бессмысленные сравнения с
==
и!=
(т.е. попытки сравнитьPerson
сPlanet
) - Гораздо проще реализуются макросы
- Объединение и пересечение предлагают гибкий способ моделирования типов
- Параметры трейтов заменяют и упрощают ранние инициализаторы
- [Псевдонимы непрозрачных типов][opaque_types] заменяют большинство случаев использования классов значений, гарантируя при этом отсутствие упаковки
- Export предложения обеспечивают простой и общий способ выражения агрегации, который может заменить предыдущий шаблон фасада объектов пакета, наследуемых от классов
- Синтаксис procedure был удален, а синтаксис varargs - изменен, чтобы сделать язык более согласованным
@infix
аннотация делает очевидным желаемое применение метода- Аннотация метода [
@targetName
]({{ site.scala3ref }}/other-new-features/targetName.html) определяет альтернативное имя метода, улучшая совместимость с Java и позволяя указывать псевдонимы для символических операторов
- Несколько различных вариантов использования ключевого слова
Демонстрация всех этих функций заняла бы слишком много места, но перейдите по ссылкам в пунктах выше, чтобы увидеть эти функции в действии. Все эти функции подробно обсуждаются на страницах New, Changed и Dropped функций в [обзорной документации][reference].
У Scala динамичная экосистема с библиотеками и фреймворками под любые требования. Список “Awesome Scala” содержит список сотен проектов с открытым исходным кодом, доступных разработчикам Scala, а Scaladex предоставляет доступный для поиска индекс библиотек Scala. Некоторые из наиболее известных библиотек перечислены ниже.
- Play Framework следует модели Ruby on Rails, чтобы стать легкой, не сохраняющей состояния, удобной для разработчиков и web архитектурой для высокомасштабируемых приложений
- Scalatra — небольшой высокопроизводительный асинхронный web framework, вдохновленный Sinatra
- Finatra — это сервисы Scala, построенные на TwitterServer и Finagle
- Scala.js — это строго типизированная замена JavaScript, обеспечивающая более безопасный способ создания надежных интерфейсных web-приложений
- ScalaJs-React поднимает библиотеку Facebook React на Scala.js и пытается сделать ее максимально безопасной для типов и удобной для Scala
HTTP(S) библиотеки:
JSON библиотеки:
Сериализация:
- BigDL (Распределенная среда глубокого обучения для Apache Spark)
- TensorFlow Scala
ФП:
Функциональное реактивное программирование (ФРП):
Как показано на этой странице, Scala обладает множеством замечательных функций высокоуровневого языка программирования, низкоуровневого языка программирования и богатой экосистемой разработчиков.
[reference]: {{ site.scala3ref }}/overview.html [multiversal]: {% link _overviews/scala3-book/ca-multiversal-equality.md %} [extension]: {% link _overviews/scala3-book/ca-extension-methods.md %} [givens]: {% link _overviews/scala3-book/ca-context-parameters.md %} [opaque_types]: {% link _overviews/scala3-book/types-opaque-types.md %}