Все значения имеют тип
В 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
В 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 |
BigInt
и BigDecimal
Для действительно больших чисел можно использовать типы BigInt
и BigDecimal
:
val a = BigInt(1_234_567_890_987_654_321L)
val b = BigDecimal(123_456.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
Два замечания о строках
Строки Scala похожи на строки Java, но у них есть две замечательные дополнительные функции:
- Они поддерживают интерполяцию строк
- Легко создавать многострочные строки
Интерполяция строк
Интерполяция строк обеспечивает очень удобный способ использования переменных внутри строк. Например, учитывая эти три переменные:
val firstName = "John"
val mi = 'C'
val lastName = "Doe"
их комбинацию можно получить так:
println(s"Name: $firstName $mi $lastName") // "Name: John C Doe"
Достаточно поставить перед строкой букву s
, а затем - символ $
перед именами переменных внутри строки.
Чтобы вставить произвольные выражения в строку, они заключаются в фигурные скобки:
println(s"2 + 2 = ${2 + 2}") // печатает "2 + 2 = 4"
val x = -1
println(s"x.abs = ${x.abs}") // печатает "x.abs = 1"
Другие интерполяторы
То s
, что вы помещаете перед строкой, является лишь одним из возможных интерполяторов.
Если вы используете f
вместо s
, вы можете использовать printf
- синтаксис форматирования стиля в строке.
Кроме того, строковый интерполятор — это всего лишь специальный метод, и вы можете определить свой собственный.
Например, некоторые библиотеки баз данных определяют очень мощный интерполятор sql
.
Многострочные строки
Многострочные строки создаются путем включения строки в три двойные кавычки:
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."
Приведение типов
Типы значений могут быть приведены следующим образом:
Например:
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
- Типы коллекций
- Методы в коллекциях
- Обзор
- Функциональное программирование
- Что такое функциональное программирование?
- Неизменяемые значения
- Чистые функции
- Функции — это значения
- Функциональная обработка ошибок
- Обзор
- Типы и система типов
- Определение типов
- Параметризованные типы