Все значения имеют тип
В 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