Как настроить scala между водителями

Обновлено: 05.07.2024

Scala – это универсальный программный типобезопасный язык JVM, который обеспечивает поддержку объектов… С тегами scala, java, языки.

Scala – это универсальный язык программирования, типобезопасный язык JVM, который обеспечивает поддержку объектно-ориентированного программирования (ООП) и функционального программирования. Scala был разработан для устранения некоторых ограничений и утомительности Java .

Scala – отличный вариант для разработчиков Java, которые хотят поднять свою карьеру на новый уровень (или для тех, кто просто устал от причуд Java). Scala теперь признан крупными компаниями как мощный язык, а именно Twitter и LinkedIn. На самом деле, согласно опросу StackOverflow за 2020 год, разработчики Scala в США имеют самые высокооплачиваемые зарплаты .

Если вы разработчик Java, который хочет перейти на Scala (или просто посмотреть, что он может предложить), вы находитесь в правильном месте. Сегодня мы познакомим вас со Scala, чтобы совершить переход.

Этот учебник с первого взгляда:

  • Scala против Java
  • Привет, мир с Scala
  • Краткое руководство по синтаксису Scala
  • Объекты и классы в Scala
  • Наследование и переопределение
  • Черты характера в Scala
  • Следующие шаги для вашего путешествия в Scala

Скала против Ява

Java известна своей сложностью и многословием. Для выполнения простых задач требуется много строк кода. Scala была разработана для создания “лучшей Java”, как и другие альтернативы, такие как Котлин и Цейлон. Однако Scala уникальна, поскольку она не пыталась оставаться слишком близкой к синтаксису Java.

Scala уничтожила ограничительные и утомительные аспекты Java в пользу улучшения языка в целом.

Это означает, что между ними существуют некоторые заметные различия и сдвиги парадигмы, поэтому у Scala кривая обучения больше , чем у Котлина. Но это того стоит: он создает чистый, простой, организованный код, который повышает вашу производительность в дальнейшем и требует гораздо меньше строк кода, чем Java.

Между этими языками существует несколько ключевых различий. Давайте разберем их.

  • Scala – это статически типизированный язык
  • Scala использует модель актора для параллелизма (вместо потоковой модели Java)
  • Scala не использует статические члены
  • Скалярные переменные неизменяемы по умолчанию
  • Scala поддерживает множественное наследование классов (не абстрактных классов)
  • Scala поддерживает отложенную оценку в отличие от Java
  • Scala предлагает поддержку перегрузки оператора
  • Scala не обеспечивает обратную совместимость
  • Scala можно использовать для функционального программирования
  • Любой метод или функция Scala обрабатывается как переменная, в то время как Java обрабатывает их как объекты
  • Scala использует черты вместо интерфейсов Java

Одним из главных преимуществ Scala является то, что он может быть выполнен на виртуальной машине Java (JVM) , что очень упрощает взаимодействие с кодом Java. Все классы из пакета java.lang по умолчанию импортируются с помощью Scala.

Однако одним из его недостатков является поддержка сообщества : существует менее подробная документация, сторонние библиотеки и присутствие сообщества, чем Java. Однако это меняется по мере того, как все больше разработчиков Java добавляют Scala в свой набор инструментов.

Для практического примера различий Java и Scala давайте посмотрим, как мы создадим список строк на обоих языках:

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

Привет, мир с Scala

Теперь, когда мы знакомы с основными различиями между Java и Scala, давайте подробнее рассмотрим код, чтобы понять, чем отличаются эти два языка. Во-первых, посмотрите на программу Hello World на Java, с которой мы знакомы:

Теперь посмотрите на эквивалентную программу в Scala. Вы сразу заметите, что это в чем-то похоже.

Итак, что здесь происходит? Как и в Java, метод main является точкой входа для нашей программы Scala, которая принимает массив строк в качестве параметра. В теле метода есть один вызов метода println с нашим приветствием в качестве аргумента. Поскольку метод main не возвращает никакого значения, его тип – Единица измерения .

То, что может вам броситься в глаза, – это использование объявления объекта . Это вводит одноэлементный объект , который представляет собой класс с одним экземпляром. Здесь мы определяем класс с именем HelloWorld и экземпляр этого класса с тем же именем.

Возможно, вы также заметили, что метод main не объявлен статическим. Scala не поддерживает статические элементы , поэтому мы определяем их как одноэлементные объекты.

Компиляция кода с помощью Scala

Компиляция нашего кода здесь также немного отличается. Для приведенного выше примера Scala мы бы использовали scalac , который работает как большинство компиляторов. Для Scala объектные файлы, создаваемые его компилятором, являются файлами классов Java.

Итак, допустим, мы сохранили нашу программу Hello World в файле с именем HelloWorld.scala . Мы бы использовали следующую команду. Это приведет к созданию нескольких файлов классов, включая один с именем Это приведет к созданию нескольких файлов классов, включая один с именем

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

Краткое руководство по синтаксису Scala

Теперь, когда мы знаем программу Hello World с помощью Scala, давайте быстро рассмотрим некоторые базовые синтаксисы Scala, которые вам необходимо знать. Мы не будем здесь определять термины, так как предполагается, что вы уже знаете их из Java или другой язык.

Переменные

Во-первых, переменные . Вот как мы объявляем переменную в Scala.

Сравните это с синтаксисом Java, который следует этой базовой структуре:

В нашем коде Scala мы объявляем переменную с именем моя первая скалярная переменная , в которой хранятся данные типа Инт и присваивается начальное значение 5 . Это неизменяемая переменная , потому что мы выбрали ключевое слово val .

  • Переменные типа val являются неизменяемыми
  • Переменные типа var являются изменяемыми переменными

Типы данных

В Scala есть иерархия типов с типом Любой вверху. Любой – это супертип, который определяет универсальные методы, такие как равно , Хэш-код и Строка/|.

Любой имеет два подкласса: Любой и Любая ссылка . AnyRef предназначен для ссылочных типов, включая типы, определенные пользователями Scala. AnyVal представляет наши типы значений, которых насчитывается девять:

  • Двойной
  • Поплавок
  • Длинный
  • Инт
  • Короткий
  • Байт
  • Обуглить
  • Единица измерения
  • Логический

Ниже у нас есть переменная любое бездействие типа Любой . Мы можем присвоить любому бездействию значение любого типа.

Вывод: Строка 5 ☺ 1.985 истинный

Строки и литералы

Строки не подпадают под AnyVal . Скорее, это литералы . Строковые литералы включают комбинацию символов, которые заключены в двойные кавычки. Синтаксис для объявления строки такой же, как и для объявления переменной любого базового типа значения.

Целочисленные литералы используются с типами значений Длинный , Int , Короткий и Байт . Scala всегда будет печатать целочисленный литерал как десятичный, независимо от того, как он объявлен. Литералы с плавающей запятой используются с Двойной и Плавать .

Выход: 1.2345 12.345 12345.0

Структуры управления

Управляющие структуры Scala являются если , в то время как , для , попробуйте , сопоставьте и вызовы функций. В Scala управляющие структуры возвращают значения, такие как функции.

Выражение if имеет следующий синтаксис:

Выражение while использует следующий синтаксис:

Общий синтаксис выражения для выглядит следующим образом:

Генератор определяет именованную переменную и присваивает ей набор значений. Мы строим его из трех частей: переменной, и выражения генератора.

Определяемые пользователем функции

Мы можем определять функции в Scala. Взгляните на этот пример, который принимает два целых числа и возвращает их сумму:

  • def – ключевое слово для определения функции
  • sum – это заданное имя функции
  • за суммой следует () . Здесь вы определяете параметры функции, разделенные запятыми.
  • (x: Двойной, y: Двойной) говорит нам, что наша функция принимает два параметра: x типа Double и y типа Double.
  • Мы определяем тип возвращаемого значения функции, Удваиваем , вставляя : Двойной после () . Вставка типа возвращаемого значения не требуется.
  • Затем мы вставляем = . Все, что происходит после этого, является телом функции. Тело функции заключено в фигурные скобки <> .

Примечание: Вы можете отказаться от использования фигурных скобок, если тело функции состоит только из одного выражения.

Объекты и классы в Scala

В отличие от Java, которая различает примитивные и ссылочные типы, Scala рассматривает все как объект , поскольку Scala является чистым языком ООП . В Scala числа также рассматриваются как объекты, поэтому у них также есть методы. Возьмем следующее арифметическое выражение:

Это выражение выполняется с помощью вызовов методов, так как оно совпадает со следующим выражением, поэтому + и * являются допустимыми идентификаторами в Scala.

Занятия

В Scala классы объявляются так же, как в Java, но классы Scala могут иметь параметры . Посмотрите на это базовое определение класса в Scala, используя ключевое слово class и ключевое слово var для определения наших свойств (называемых полями в Scala).

Чтобы определить методы нашего класса, мы используем этот синтаксис:

И теперь мы можем создавать экземпляры наших классов, используя val .

Вызов функций внутри функций

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

Взгляните на этот пример ниже, где мы вызываем функцию square в другой функции squareSum .

Наследование и переопределение

Существует несколько типов наследования , поддерживаемых Scala:

  • Одноуровневое наследование: Один класс наследуется от одного другого класса
  • Многоуровневое наследование: Один класс расширяет другой, который затем расширяет другой
  • Множественное наследование: Один класс наследуется от нескольких базовых классов

В Scala все классы наследуются от суперкласса, и когда суперкласс не объявлен, Scala использует scala. AnyRef . Вы можете переопределять методы, унаследованные от суперкласса, но вы должны явно указать это с помощью модификатора override . Например:

Черты характера с помощью Scala

Scala использует черты, которые похожи на Интерфейсы Java . Подобно наследованию в Scala, как описано выше, класс также может импортировать код из одного или нескольких признаков. Когда это происходит, класс реализует интерфейс данного признака и весь код в этом признаке.

Думайте об этом как о способе реализации многократного использования в коде Scala.

основными свойствами Признака являются:

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

В Scala мы можем использовать расширения ключевое слово для расширения признака. Затем мы реализуем любые абстрактные члены с переопределением ключевое слово:

Следующие шаги для вашего путешествия в Scala

Поздравляю с тем, что вы дошли до конца. Теперь вы на верном пути к переходу на роль разработчика Scala. Как вы можете видеть, Scala позволяет вам использовать ваши существующие навыки Java. Еще многое предстоит узнать о Scala, и практическая практика будет необходима для овладения этим языком.

Для следующих шагов мы рекомендуем следующие концепции:

  • Дженерики с Scala
  • Функции более высокого порядка
  • Каррирование
  • Библиотека коллекций Scala

Чтобы начать работу с этими концепциями и начать строить с помощью Scala, ознакомьтесь с учебным курсом Изучайте Scala с нуля. Этот курс поможет вам оставаться на шаг впереди, создавать потрясающие масштабируемые приложения и изучать очень желанный новый язык программирования. К концу вы полностью перейдете с Java на Scala!


Этот первый раздел доступен на Medium, но остальную часть этого руководства можно найти на странице проекта Github по ссылке ниже:

Scala - это объектно-ориентированный и функциональный язык программирования. Это наиболее тесно связано с Java, поэтому Java-программисты должны иметь возможность изучать его. Тем не менее, Scala разработан, чтобы быть более кратким и иметь функции функциональных языков программирования.

Spark - это инфраструктура кластерных вычислений с открытым исходным кодом, предназначенная для обработки больших данных. Это написано в Scala. Spark можно запустить в Python (PySpark) и R (SparkR и Спарклер); Однаколучшее представлениес помощью Spark можно добиться в Scala.

Я предложу некоторые другие источники как альтернативы, так и ссылки. Курсы Хосе Портильи по Удеми великолепны, и мой блог будет неукоснительно следовать структуре его «Scala и Spark для больших данных и машинного обучения" курс. Если вы учитесь лучше в формате видео, я очень рекомендую этот курс.

Первая задача - скачать Scala. Следует признать, что это может быть одной из наиболее сложных частей процесса. Вам нужно будет пройти несколько шагов. Если вы используете Windows 10, я рекомендую следующее руководство на YouTube:

Вы можете сами решить, хотите ли вы установить SBT, так как есть другие варианты запуска Scala (например,IntelliJ).

Если вы используете ОС на базе Linux, вот похожее видео для вас. Я не могу ручаться за это, но это от того же автора.

Наконец, вот несколько инструкций для Mac.

Хотя я обнаружил, что установка Scala более сложна, чем Python или R, в Интернете есть множество ресурсов, если вы испытываете трудности. Хорошей новостью является то, что это, вероятно, самая сложная часть для большинства людей.

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

Вы, очевидно, можете использовать и другие опции, такие как Atom или Sublime. Кроме того, если вы хотите использовать полную IDE,IntelliJхороший выбор, и естьПлагин Scalaдля этого.

Если вы хотите использовать VS Code, но у вас его еще нет, скачайте егоВот,


Вы также можете рассмотреть некоторые другие плагины Scala. Я не особо возился с остальными, но я также скачал плагин Scala Syntax.

В любом случае, теперь вы должны быть настроены для запуска файлов Scala.

Это запустит Spark в локальном режиме, который мы будем использовать для изучения основ Scala.

Давайте начнем с простого оператора печати. Операторы печати в Scala похожи на Java, но немного более лаконичны.

И вуаля! Теперь вы запускаете свою первую программу Scala.

С этим вы должны получить распечатку.

Вот и все для этой части 1. Часть 2 охватывает типы данных; проверить это напроект Github репо,

val - константа
var - Изменяемая переменная:
- все типы являются классами (нет встроенных типов): Byte, Char, Short, Long, Float, Double, Boolean
- String используется java.lang.String но добавляет дополнительные функции (StringOps, RichInt, RichDouble . )

Операторы

Условия

- Условия возвращают значение это удобней, т.к. может быть использовано для инициализации const
аналогом c++ является x > 0 ? 1 : -1

Вывод в консоль

, где:
$a - переменная
$<> - выражение

Циклы

- while / do - аналогично java
- цикл for работает по принципу foreach - перебора элементов последовательности: 1 to n - генерирует последовательность чисел, которая обходится последовательно
последовательность может быть любая - выражение или просто строка
- нет break и continue
- в for может быть несколько итераторов через ; и выражение может содержать условие:
т.е. каждая итерация i запускает цикл j (аналог вложенного цикла с условием) и накладывает фильтр, чтобы в j не было пересечений с i
- циклы могут использоваться для генераций колекций

Функции

- Однострочный вариант: - Многострочный: - Указание типа обязательно для рекурсии, иначе нет: - Можно использовать return для немедленного выхода из функции
- параметр функции может иметь значение по умолчанию: - передавать параметры можно по имени в любом порядке: - функция с переменным числом параметров: - Чтобы передать список как несколько параметров, нужно добавить : _* - def w = .
логически похоже на переменную, которая каждый раз переинициализируется при обращении

- Способы передачи параметров в функцию:
call by value - каждый аргумент расчитывается единожды и передается в функцию
call by name (по ссылке) - аргумент не вычисляется, если он не используется в теле функции (вычисление происходит внутри функции)
т.е. если в параметре сложное выражение, то оно будет выполнено несколько раз (но если оно не испольузется внутри, то не будет ненужного вычисления как в call by value)

- Частичные (partial) функции:
partial функция - реализуется чреез pattern matching и может работать только для нужных case:
определена ли функция для значения можно проверить через isDefinedAt если вызывать для несуществующего значения, то будет исключение: может применяться в lambda функциях как параметр и будет вызываться только для применимых значений:
- Возврат Option значения
обработка ситуации NULL указателя через Option и getOrElse или обработка None
- Исключающее ИЛИ в параметрах или возвращаемом значении
Either[A, B] - исключающее или как возвращаемый параметр - может использоваться как обработку ошибок без Try
"Right - это правильно". Поэтому же map и flatMap применяются к правильной ветви, то есть к правой. И "хороший" результат оборачивают в Right, а ошибку в Left.
- чтобы перехватить иключение, можно использовать объект Try:

Процедуры

Ленивые переменные

Операция для инициализации w вызовется при первом обращении.

Исключения

Аналогично java: - в scala нет проверки на обязательность исключения во время компиляции как в java
так писать не нужно:
- перехват exception идет через case:

Массивы

- Фиксированный массив: - с начальной инициализацией: - Переменной длины:
Аналог java arraylist: - добавить элемент в массив: - несколько значений (каждое станет значением) - обход массива:
-- если индекс не нужен: -- если нужен индекс: until почти то же самое, что to , создается множество -1 значение
- yeld - обход с преобразованием в новый массив (описано в циклах)
- обход и фильтрация массива: - arr.indices - список индексов (ключей) массива
- встроенные методы: sum, max, count(_ > 0), sorted (_ на 1 to 10, 1 -> 10
- опрделение своего оператора как в java: - f(arg1, arg2, . ) вызовет f.apply(arg1, arg2, . ) , если метода f нет в классе
- f(arg1, arg2, . ) = value - если слева от =, то вызовет update
это используется в массивах:
scores("Bob") = 100
- unapply - Обратная операция - объект разворачивается в переменные: использование: val Fraction(a, b) = f;
- динамические методы и переменные: -- динамический вызов транслируется в : -- person.lastName = "Doe"
транслируется в: реализовывать функцию нужно самим

Функции высшего порядка

- функцию можно положить в переменную: _ означает необходимость параметра для функции

- Общая сигнатура функции высшего порядка:
f - тип функции, которая принимает A и возвращает B - метод класса: переменная: (параметр: тип).функция(параметр: тип) переменная: (входные параметры) => выходной параметр = вызов функции с параметрами
- анонимная функция можно передавать ее как параметр, без переменных: более короткая запись: - функция, параметром которой является функция: - функция возвращает функцию: в функцию mulBy положена функция "(x : Double) => factor * x" - каррирование - преобразование ф. с 2 параметрами в 2 функции с 1 параметром:
каррирование удобно для создания новых функций:
т.е. это цепочка из 2 функций вложенных друг в друга(если параметров каррирования 2)
первый описывает преобразование
второй статичные параметры, которое использует действие (преобразование)

- передача абстрактного кода: - return может быть использован чтобы определить тип возвращаемых данных, если одновременно используется анонимная функция без типа, которая должна посчитать результат

- monad - Монада
имеет 2 обязательных метода:
-- flatMap (примеменяет функцию f(T): монада(T) для всех элементов)
-- unit (T->монада[T]) - помещение элемента во внутренний контейнер (int в List/Set/Map)
К примеру, List - монада, т.к. помещает элементы во внутренний контейнер-список над которым можно применить flatmap
Правила монады:
-- ассоциативность: m.flatMap(f).flatMap(g) == m.flatMap(x=> f(x).flatMap(g))
-- левый unit: unit(x).flatMap(f) == f(x) //вызов flatmap c функцией f над list из 1 элемента = вызову f(один элемент)
-- правый unit: m.flatMap(unit) == m (m - уже монада = unit(x))

Коллекции

- наследование объектов: - Преобразование типов через: .to*
- все коллекции по умолчанию неизменяемые (Immutable)
т.е. если мы изменяем коллекцию, то создается копия с изменениями
- Vector - immutable расширяемый массив (ArrayBuffer - muttable)
Технически хранится в виде b-дерева, с элементами в узле (32 элемента в блоке)
- Range - последовательность чисел
Технически хранит: начало, конец и шаг
- на последовательностях сделано: Stack, Queue, Prior Queue, ListBuffer

- for yield - более короткая замена для Map/flatmap/withfilter это аналог более длинной записи: - можно приводить java объекты к scala коллекциям

Сопоставление с образцом

- аналог switch: -- не нужен brake - он есть по умолчанию
-- _ - если не будет, то выкинется исключение при проверке
-- можно перечислять несколько значений через |
-- в case может быть любое логическое условие: -- присвоение идет произвольной переменной за =>
-- сопоставление может идти с типом переменной: - сопоставление массива 2 переменным и всего остального последовательности rest: - сопоставление ключа и значения ассоц. массива может быть в цикле: - сопоставление может идти по типу класса: - объект можно скопировать с изменением параметра: - для сопоставления с пустым значением можно использовать тип Some - сравнение с коллекциями: - для сопоставления с образцом класса, нужен специальный case класс:

Аннотации

Диррективы компилятору
- определение собственной аннотации - volatile поле, которое можно менять из разных потоков
jvm выключает оптимизации: помещение в кэше процессора и т.д.
Изменения данных всегда будет видно всем процессам программы, т.к. обновление будет идти через общее хранилище. - несериализуемое поле - методы на c++ - Контролируемые исключения: - генерация геттеров/сеттеров:
- рекурсивный вызов - может быть преобразован к циклу комплиятором
Рекурсивный вызов самостоятелен (не является частью выражения) - может быть преобразован к циклу: Значение + рекурсивный вызов не может автоматически преобразоваться к циклу, т.к. требуется дойти до конца рекурсии, а потом раскручивать вызовы в обратном порядке:
- @switch - трансформировать swith в таблицу переходов, что оптимальнее if
- @elidable(500) - метод после 500 сборки удалится из скомпилированного кода
- def allDifferent[@specialized(Long, Double) T](x: T, y: T, z: T) = . - генерация специализированных функций под каждый тип
- @deprecated(message = "Use factorial(n: BigInt) instead") - устаревшая функция

Обработка XML

- создание xml переменной: - обработка элементов: - доступ к атрибуту: - обход всех атрибутов: - вставка переменной в xml: - xpath поиск:
-- поиск непосредственного тега body - любой тег - тег li -- поиск тега img на любом уровне вложенности - case => . - выберется если img с любым содержанием
- объекты неизменяемые, для изменения атрибута нужно его скопировать: - для трансформации можно использовать класс с case преобразования внутри:
- загрузка xml: - загрузка с сохранением комментариев: - сохранение xml:

Обобщенные типы

- псевдоним для типа: и обобщенного: также можно указывать ограничения: типы компоненты - псевдонимы без определения: компонентный тип с уточнением:

Дополнительные типы

- составление цепочек вызовов: для того, чтобы она работала и для наследников базового класса нужно указывать "this.type": - псевдоним для длинного типа: - необходимость передачи типа данных с методом "append" - внедрение зависимостей: - абстрактный тип: - то же самое через обобщенный тип:

Неявные преобразования

- функции с неявными преобразованием параметров Int к Fraction - добавление своей функции в стандартный класс:
-- добавляем функцию read -- неявное преобразование класса File к RichFile: -- вместо функции можно использовать класс: дальше обычно создаем объект File
помещаем функции в файл
и обязательно импортируем без префикса: чтобы минимизировать число неявных преобразований, вызов можно делать внутри кода класса
- необязательные параметры: можно заранее объявить неявный разделитель: - Неявная передача параметра ord в зависимости от типа другого параметра (A) Параметр можно задать явно: sort(xs)(Ordering.Int.reverse)
- из 2 реализаций implicit выбирается наиболее точная:
-- по типу -- по вложенности
- можно посмотреть, что подставится в implicit для заданного типа вызовом:

Конкурентное программирование Scala

Реализация многопоточности в JVM

- поток в jvm это обертка над потоком ОС (в отличии от python)
- java-style поток: - простой способ вернуть данные из потока - это объявить глобальную переменную, но использовать ее после join
- объявление синхронизированной функции: - самодельный пул потоков:
-- пул ожидающий работы (wait): -- помещение программы в пул и нотификация, что нужно перестать делать wait -- остановить пул при установке некого флага: - один из способов побороть deadlock - синхронизировать ресурсы в 1 последовательности, чтобы не получилось перекрестной взаимоблокировки
если ресурсы блокируются в 1 последовательности, то 2 поток просто дождется окончания 1
Способ: перед трансфером получить атомарный счетчик в объект и перевод всегдя делается с объекта у которого меньший счетчик, чтобы обеспечить одинаковую последовательность блокировок:

Атомарные изменчивые переменные

такие переменные изменяются за 1 такт, поэтому не могут меняться одновременно в нескольких потоках
на уровне процессора это операция: compareAndSet - установить значение, если compare выполнилось удачно
полный список описан тут: java.util.concurrent.atomic: AtomicBoolean, AtomicInteger, AtomicLong и AtomicReference
Пример использования: Аналог через synchronized: - блоки синхронизации могут вкладываться друг в друга - это лучше, чем делать 1 глобальный лок: - lazy переменные инициируются 1 раз при первом обращении
для проверки инициализации используются дополнительное атомарное поле-флаг
- muttable объекты нужно использовать с блокировками
- шаблон producer / consumer
между потребителем и производителем находится конкурентная очередь с данными:
- BlockingQueue - реализация в Scala: add/remove/element - с исключениями (poll/ofer/peak - со специальным значение) (take, put - блокирующие)
-- ArrayBlockingQueue - очередь фиксированного размера
-- LinkedBlockingQueue - неограниченная очередь (когда производители гарантированно работают быстрее потребителей)

- Конкурентные объекты: -- concurrent.TrieMap() - позволяет обходить массив по его копии, что не блокирует его самого и не дает получить изменяемые данные
-- ConcurrentSkipListSet[Int] //lock free структуры (оптимистическая блокировка с атомарной проверкой)

Параллельные коллекции данных

- параллельный запуск обработки колекции = вызов функции par -- можно распараллелить цикл: -- преобразование параллельной коллекции в последовательную:
- Left операторы не могут обрабатываться параллельно, т.к. используют результат предыдущего выполнения
- Reduce операции сохраняющий тип данных : (A, A) => A могут быть распараллены
-- Дополнительно должно выполняться условие: a op b == b op a
( к примеру сложение просто парралелиться, но не вычитание, т.к. оно зависит от порядка )
- Если хочется результат другого типа, отличного от параметров, то нужно использовать aggregate - Если нужно, чтобы функция принимала или обычную или параллельную коллекцию, то нужно использовать тип GenSeq это интерфейс обоих контейнеров
- Установка уровня параллельности для блока: --- Установка параллельности для оператора: - для преобразования последовательной коллекции к параллельной используются сплиттеры (надстройка над итератором)
-- линейноссылочные структуры List/Stream не имеют эффективного алгоритма Split
при вызове par у этих структур они сначала преобразуются к обычным массивам
- Пример создания своей параллельной коллекции (в данном случае строки): сплиттер должен быть отнаследован от трейта: - необязательные функции:
psplit - ручное задание размеров для сплита
- пример сплита на 2 части: - psplit создает сплиттер с половиной строки: - Комбинаторы - слияние сплитов обратно при использовании методов трансформации: map, filter groupBy

Объекты Future

- создание отдельного потока из пула потоков: -- другой вариант ожидания: -- альтернативный вариант без блокировки:
по результату работы асинхронно вызовется функция: -- объект Future должен возвращать результат или генерировать exception в случае ошибки

Реактивное программирование

События хранятся в сигнале - это иммутабельный объект
- значение в объекте можно менять
- оно будет автоматически проброшено на все зависимые сигналы
Signal = значение , выражение , список наблюдателей + update, который обновит значение используя выражение и оповестит всех наблюдателей о необходимости update - Сравнение классического и реактивного подхода:
-- Классический подход: -- reactive подход: Код подписчика, который считает сумму всех балансов: - зависимое событие:

Программная транзакционная память

- в основе лежит операция atomic
для работы нужна библиотека org.scala-stm атомарные операции не подвержены взаимоблокировкам, из-за этого они используются в оптимистических блокировках:
-- перед началом запоминается состояние памяти
-- если оказывается при записи, что область была изменена, то транзакция рестартуется
- для применения оптимистичной блокировки над переменной, нужно использовать ссылочный тип: - минус оптимистических блокировок:
-- рестарт транзакции, так что в транзакции нельзя вызывать неоткатываемые транзакции - к примеру http запрос
-- дополнительная нагрузка из-за рестарта
- для 1 минуса - "повторный вызов неоткатываемого запроса", можно использовать событие - aftercommit: - в случае исключения внутри atomic - она целиком откатывается
- повторение транзакции, но с таймаутом в 1с: - бесконечный повтор с интервалом в 1с: - для локальных переменных нужно использовать TxnLocal - она индивидуальна в каждой транзакции - транзакционный массив: - транзакционный словарь: -- словарь имеет возможность получить неизменяемый снапшот:

Акторы

[Scala] Конфигурация установки Scala и базовый синтаксис

1. Введение в Scala

2. Установка Scala

(1) Настройте Scala под Linux

  1. Распакуйте установочный пакет
  2. Настройте переменные среды, как показано в файле конфигурации / etc / profile:

(2) Настройте Scala под Windows

3. Использование переводчика Scala

(1) REPL: чтение-> оценка-> печать-> цикл. Интерпретатор scala, также известный как REPL, быстро скомпилирует код scala в байт-код, а затем передаст его JVM для выполнения.
(2) Автоматическое завершение: в командной строке scala> вы можете использовать клавишу Tab для автоматического завершения.

Например,Тип res2.to, Нажмите клавишу Tab, интерпретатор отобразит следующие параметры: toCharArray, toLowerCase, toString, toUpperCase. Поскольку невозможно определить, какой из них вам нужно завершить в данный момент, вам будут предоставлены все варианты.
Например, введите res2.toU и нажмите клавишу Tab, и он сразу завершит вас как res2.toUpperCase.

(3) В определения программы Scala необходимо добавить объект

Обобщение: scalac HelloWorld.scala
выполнить: scala HelloWorld

4. Типы переменных Scala и операторы

(1) Объявление переменной val: вы можете объявить переменную val, чтобы сохранить результат вычисления выражения.

В последующем эти константы можно продолжать использовать,

Но после того, как константа объявлена, ее значение не может быть изменено,

(2) Объявление переменной var: если вы хотите объявить ссылку, значение которой можно изменить, вы можете использовать переменную var.

Например, var myresult = 1, myresult = 2

Однако в программах scala, как правило, рекомендуется использовать val, который является константой, поэтому, например, в большой сложной системе, подобной spark, требуется большой объем передаваемых данных по сети. Если вы используете var, вы можете опасаться, что значение будет изменено по ошибке. Подобные функции используются при проектировании и разработке больших и сложных систем на Java. Обычно мы проектируем объекты, передаваемые другим модулям / компонентам / сервисам, как неизменяемые классы. Определения констант Java, такие как final, также используются для предотвращения изменения значений переменных. Тем самым улучшается надежность (робастность) и безопасность системы.
(3) Укажите тип: объявляете ли вы переменную val или переменную var, вы можете указать тип вручную. Если вы не укажете его, scala автоматически выведет тип на основе значения.

Например, val name: String = null
Например, val name: Any = "leo"

(4) Объявление нескольких переменных: несколько переменных могут быть объединены для объявления.

Например, val name1, name2: String = null
Например, val num1, num2 = 100


(5) Основные типы данных: байт, символ, короткий, внутренний, длинный, плавающий, двойной, логический.
На первый взгляд, он выглядит так же, как тип упаковки базовых типов данных Java, но в scala нет концепции базовых типов данных и типов упаковки, и все они являются унифицированными классами. Scala будет отвечать за преобразование основных типов данных и ссылочных типов.
Используя вышеуказанные типы, вы можете напрямую вызывать большое количество функций, например, 1.toString (),1.to(10). Есть несколько других основных типов, включая: Единица, Нуль, Ничто, Любой.
Диаграмма отношений базового типа Scala:

(6) Расширенный тип типа: Scala использует множество расширенных классов для добавления сотен расширенных функций или функций к типу данных.

(7) За именем переменной должно следовать двоеточие, а первая буква типа должна быть заглавной

Подчеркивание представляет собой заполнитель. Обратите внимание, что тип должен быть указан после этой записи.

Единица эквивалентна пустоте
Нулевое нулевое значение или нулевая ссылка
Ничто не означает никакого значения
Любой означает, что это суперкласс всех типов, все типы наследуются от него.

(7) Основные операторы: арифметические операторы Scala ничем не отличаются от арифметических операторов java, таких как +, -, *, /,% и т. Д., А также, &, |, ^, >>, 18) 1 еще 0

Вы можете назначить выражение if переменной

Например, val isAdult = if (age> 18) 1 else 0

Еще один способ написания,

var isAdult = -1; if(age > 18) isAdult = 1 else isAdult = 0,

Но обычно используют последний способ
(2) Вывод типа выражения if: поскольку выражение if имеет значение, а типы значений предложений if и else могут отличаться, каково значение выражения if на данный момент Как насчет типа? Scala автоматически выведет и примет общий родительский тип двух типов.

Если if не сопровождается else, тогда значением по умолчанию else является Unit, которое также представлено (), аналогично void или null в java.

Положите операторы if в несколько строк: по умолчанию REPL может интерпретировать только одну строку операторов, но если выражения обычно необходимо размещать в несколько строк. Вы можете использовать <>, например, следующее или использовать: paste и ctrl + D.

if(age > 18) < “adult”
> else if(age > 12) “teenager” else “children”

(3) оператор завершения, блочное выражение
По умолчанию scala не требует завершения оператора, и каждая строка по умолчанию обрабатывается как оператор.
Поместите несколько операторов в одну строку: если вы хотите поместить несколько операторов в одну строку, вы должны использовать терминатор операторов

Например, используя точку с запятой в качестве разделителя операторов, var a, b, c = 0, если (a

Интеллектуальная рекомендация


IOS CocoaPods Не удалось найти спецификацию для решения проблемы `xxxx`

Вчера Alibaba Cloud открыла исходный код coobjc, поэтому я хотел узнать о конкретном эффекте, но когда я делал купол, установку модуля установить не удалось. Конкретный эффект показан на рисунке ниже.

iOS-определение с возвращаемым значением

использование: Результат печати: Определение этого макроса: Пустая строка возвращает пустую, а непустая строка возвращает сама себя.

Примечания (изменение стиля запрещено, настройка может вводить только цифры)

layui --- Запрет на изменение стиля в настройках ввода можно вводить только цифры .


Разработка интерфейса - интегрированный интерфейсный документ (чванство)

Прежде чем войти в тему, позвольте мне рассказать о проблемах, возникающих в реальной работе. Это не традиционная нативная разработка APP или текущая гибридная разработка H5. Поскольку интерфейс и бэк.

Читайте также: