Все значения имеют тип
В Scala все значения имеют тип, включая числовые значения и функции. На приведенной ниже диаграмме показано подмножество иерархии типов.
Иерархия типов Scala
Any - это супертип всех типов, также называемый верхним типом (the top type).
Он определяет универсальные методы, такие как equals, hashCode и toString.
У верхнего типа Any есть подтип Matchable, который используется для обозначения всех типов,
для которых возможно выполнить pattern matching (сопоставление с образцом).
Важно гарантировать вызов свойства “параметричность”, что вкратце означает,
что мы не можем сопоставлять шаблоны для значений типа Any, а только для значений, которые являются подтипом Matchable.
Справочная документация содержит более подробную информацию о Matchable.
Matchable содержит два важных подтипа: AnyVal и AnyRef.
AnyVal представляет типы значений.
Существует несколько предопределенных типов значений, и они non-nullable:
Double, Float, Long, Int, Short, Byte, Char, Unit и Boolean.
Unit - это тип значения, который не несет никакой значимой информации. Существует ровно один экземпляр Unit - ().
AnyRef представляет ссылочные типы. Все типы, не являющиеся значениями, определяются как ссылочные типы.
Каждый пользовательский тип в Scala является подтипом AnyRef.
Если Scala используется в контексте среды выполнения Java, AnyRef соответствует java.lang.Object.
В языках, основанных на операторах, void используется для методов, которые ничего не возвращают.
В Scala для методов, которые не имеют возвращаемого значения,
такие как следующий метод, для той же цели используется Unit:
def printIt(a: Any): Unit = println(a)
Вот пример, демонстрирующий, что строки, целые числа, символы, логические значения и функции являются экземплярами Any
и могут обрабатываться так же, как и любой другой объект:
val list: List[Any] = List(
"a string",
732, // число
'c', // буква
'\'', // Экранированный символ
true, // булево значение
() => "an anonymous function returning a string"
)
list.foreach(element => println(element))
Код определяет список значений типа List[Any].
Список инициализируется элементами различных типов, но каждый из них является экземпляром scala.Any,
поэтому мы можем добавить их в список.
Вот вывод программы:
a string
732
c
'
true
<function>
Типы значений в Scala
Как показано выше, числовые типы Scala расширяют AnyVal, и все они являются полноценными объектами.
В этих примерах показано, как объявлять переменные этих числовых типов:
val b: Byte = 1
val i: Int = 1
val l: Long = 1
val s: Short = 1
val d: Double = 2.0
val f: Float = 3.0
В первых четырех примерах, если явно не указать тип, то тип числа 1 по умолчанию будет равен Int,
поэтому, если нужен один из других типов данных — Byte, Long или Short — необходимо явно объявить эти типы.
Числа с десятичной дробью (например, 2.0) по умолчанию будут иметь тип Double,
поэтому, если необходим Float, нужно объявить Float явно, как показано в последнем примере.
Поскольку Int и Double являются числовыми типами по умолчанию, их можно создавать без явного объявления типа данных:
val i = 123 // по умолчанию Int
val x = 1.0 // по умолчанию Double
Также можно добавить символы L, D, and F (или их эквивалент в нижнем регистре)
для того, чтобы задать Long, Double или Float значения:
val x = 1_000L // val x: Long = 1000
val y = 2.2D // val y: Double = 2.2
val z = -3.3F // val z: Float = -3.3
Вы также можете использовать шестнадцатеричное представление для форматирования целых чисел
(обычно это Int, но также поддерживается суффикс L для указания Long):
val a = 0xACE // val a: Int = 2766
val b = 0xfd_3aL // val b: Long = 64826
Scala поддерживает множество различных способов форматирования одного и того же числа с плавающей запятой, например:
val q = .25 // val q: Double = 0.25
val r = 2.5e-1 // val r: Double = 0.25
val s = .0025e2F // val s: Float = 0.25
В Scala также есть типы String и Char, которые обычно можно объявить в неявной форме:
val s = "Bill"
val c = 'a'
Как показано, заключайте строки в двойные кавычки или тройные кавычки для многострочных строк, а одиночный символ заключайте в одинарные кавычки.
Типы данных и их диапазоны:
| Тип данных | Возможные значения |
|---|---|
| Boolean | true или false |
| Byte | 8-битное целое число в дополнении до двух со знаком (от -2^7 до 2^7-1 включительно) от -128 до 127 |
| Short | 16-битное целое число в дополнении до двух со знаком (от -2^15 до 2^15-1 включительно) от -32 768 до 32 767 |
| Int | 32-битное целое число с дополнением до двух со знаком (от -2^31 до 2^31-1 включительно) от -2 147 483 648 до 2 147 483 647 |
| Long | 64-битное целое число с дополнением до двух со знаком (от -2^63 до 2^63-1 включительно) (от -2^63 до 2^63-1 включительно) |
| Float | 32-разрядный IEEE 754 одинарной точности с плавающей точкой от 1,40129846432481707e-45 до 3,40282346638528860e+38 |
| Double | 64-битный IEEE 754 двойной точности с плавающей запятой от 4,94065645841246544e-324 до 1,79769313486231570e+308 |
| Char | 16-битный символ Unicode без знака (от 0 до 2^16-1 включительно) от 0 до 65 535 |
| String | последовательность Char |
Строки
Строки Scala похожи на строки Java, хотя в отличие от Java (по крайней мере, до Java 15) в Scala легко создавать многострочные строки с тройными кавычками:
val quote = """The essence of Scala:
Fusion of functional and object-oriented
programming in a typed setting."""
Одним из недостатков этого базового подхода является то, что строки после первой строки содержат отступ и выглядят следующим образом:
"The essence of Scala:
Fusion of functional and object-oriented
programming in a typed setting."
Если важно исключить отступ, можно поставить символ | перед всеми строками после первой
и вызвать метод stripMargin после строки:
val quote = """The essence of Scala:
|Fusion of functional and object-oriented
|programming in a typed setting.""".stripMargin
Теперь все строки выравниваются по левому краю:
"The essence of Scala:
Fusion of functional and object-oriented
programming in a typed setting."
Строки Scala также поддерживают мощные методы интерполяции строк, о которых мы поговорим в следующей главе.
BigInt и BigDecimal
Для действительно больших чисел можно использовать типы BigInt и BigDecimal:
val a = BigInt(1_234_567_890_987_654_321L)
val b = BigDecimal(123456.789)
Где Double и Float являются приблизительными десятичными числами,
а BigDecimal используется для точной арифметики, например, при работе с валютой.
BigInt и BigDecimal поддерживают все привычные числовые операторы:
val b = BigInt(1234567890) // scala.math.BigInt = 1234567890
val c = b + b // scala.math.BigInt = 2469135780
val d = b * b // scala.math.BigInt = 1524157875019052100
Приведение типов
Типы значений могут быть приведены следующим образом:
Например:
val b: Byte = 127
val i: Int = b // 127
val face: Char = '☺'
val number: Int = face // 9786
Вы можете привести к типу, только если нет потери информации. В противном случае вам нужно четко указать приведение типов:
val x: Long = 987654321
val y: Float = x.toFloat // 9.8765434E8 (обратите внимание, что требуется `.toFloat`, потому что приведение приводит к потере точности)
val z: Long = y // Ошибка
Вы также можете привести ссылочный тип к подтипу. Это будет рассмотрено в книге позже.
Nothing и null
Nothing является подтипом всех типов, также называемым нижним типом (the bottom type).
Нет значения, которое имело бы тип Nothing.
Он обычно сигнализирует о прекращении, таком как thrown exception, выходе из программы или бесконечном цикле -
т.е. это тип выражения, который не вычисляется до определенного значения, или метод, который нормально не возвращается.
Null - это подтип всех ссылочных типов (т.е. любой подтип AnyRef).
Он имеет единственное значение, определяемое ключевым словом null.
В настоящее время применение null считается плохой практикой.
Его следует использовать в основном для взаимодействия с другими языками JVM.
Опция компилятора opt-in изменяет статус Null, делая все ссылочные типы non-nullable.
Этот параметр может стать значением по умолчанию в будущей версии Scala.
В то же время null почти никогда не следует использовать в коде Scala.
Альтернативы null обсуждаются в главе о функциональном программировании и в документации API.
Contributors to this page:
Contents
- Введение
- Возможности Scala
- Почему Scala 3?
- Почувствуй Scala
- Пример 'Hello, World!'
- REPL
- Переменные и типы данных
- Структуры управления
- Моделирование данных
- Методы
- Функции первого класса
- Одноэлементные объекты
- Коллекции
- Контекстные абстракции
- Верхнеуровневые определения
- Обзор
- Первый взгляд на типы
- Интерполяция строк
- Структуры управления
- Моделирование предметной области
- Инструменты
- Моделирование ООП
- Моделирование ФП
- Методы
- Особенности методов
- Main методы в Scala 3
- Обзор
- Функции
- Анонимные функции
- Параметры функции
- Eta расширение
- Функции высшего порядка
- Собственный map
- Создание метода, возвращающего функцию
- Обзор
- Пакеты и импорт
- Коллекции в Scala
- Типы коллекций
- Методы в коллекциях
- Обзор
- Функциональное программирование
- Что такое функциональное программирование?
- Неизменяемые значения
- Чистые функции
- Функции — это значения
- Функциональная обработка ошибок
- Обзор
- Типы и система типов
- Определение типов
- Параметризованные типы
- Пересечение типов
- Объединение типов
- Алгебраические типы данных
- Вариантность
- Непрозрачные типы
- Структурные типы
- Зависимые типы функций
- Другие типы
- Контекстные абстракции
- Методы расширения
- Параметры контекста
- Контекстные границы
- Given импорты
- Классы типов
- Многостороннее равенство
- Неявное преобразование типов
- Обзор
- Параллелизм
- Scala утилиты
- Сборка и тестирование проектов Scala с помощью Sbt
- Рабочие листы
- Взаимодействие с Java