Классы в Scala являются основами для создания объектов. Они могут содержать методы, константы, переменные, типы, объекты, трейты и классы, которые в совокупности называются членами. Типы, объекты и трейты будут рассмотрены позже в ходе нашего обзора.
Объявление класса
Минимальное объявление класса - это просто ключевое слово class
и его имя. Имена классов должны быть написаны с заглавной буквы.
class User
val user1 = new User
Ключевое слово new
используется для создания экземпляра класса.
class User
val user1 = User()
Чтобы создать экземпляр класса, мы вызываем его как функцию: User()
.
Также можно явно использовать ключевое слово new
: new User()
- хотя обычно это опускается.
User
имеет конструктор по умолчанию, который не принимает аргументов, так как конструктор не был определен. Однако обычно используется и конструктор, и тело класса. Пример объявления класса Point приведен ниже:
class Point(var x: Int, var y: Int) {
def move(dx: Int, dy: Int): Unit = {
x = x + dx
y = y + dy
}
override def toString: String =
s"($x, $y)"
}
val point1 = new Point(2, 3)
println(point1.x) // выводит 2
println(point1) // выводит (2, 3)
class Point(var x: Int, var y: Int):
def move(dx: Int, dy: Int): Unit =
x = x + dx
y = y + dy
override def toString: String =
s"($x, $y)"
end Point
val point1 = Point(2, 3)
println(point1.x) // выводит 2
println(point1) // выводит (2, 3)
В этом классе у Point
есть четыре члена: переменные x
и y
и методы move
и toString
.
В отличие от многих других языков, основной конструктор находится в сигнатуре класса (var x: Int, var y: Int)
. Метод move
принимает два целочисленных аргумента и возвращает значение Unit ()
- это пустое множество, которое не содержит никакой информации. Примерно соответствует void
в Java-подобных языках. С другой стороны, toString
не принимает никаких аргументов, а возвращает значение String
. Поскольку toString
переопределяет toString
из AnyRef
, он помечается ключевым словом override
.
Конструкторы
Конструкторы могут иметь необязательные параметры, если указать их значения по умолчанию как в примере:
class Point(var x: Int = 0, var y: Int = 0)
val origin = new Point // x и y оба равны 0
val point1 = new Point(1) // x равен 1, а y равен 0
println(point1) // выводит (1, 0)
class Point(var x: Int = 0, var y: Int = 0)
val origin = Point() // x и y оба равны 0
val point1 = Point(1) // x равен 1, а y равен 0
println(point1) // выводит (1, 0)
В этой версии класса Point
, x
и y
имеют значение по умолчанию 0
, поэтому аргументов не требуется. Однако, поскольку конструктор считывает аргументы слева направо, если вы просто хотите передать значение y
, то вам нужно будет указать задаваемый параметр.
class Point(var x: Int = 0, var y: Int = 0)
val point2 = new Point(y = 2)
println(point2) // выводит (0, 2)
class Point(var x: Int = 0, var y: Int = 0)
val point2 = Point(y = 2)
println(point2) // выводит (0, 2)
Что также является хорошей практикой для повышения ясности кода.
Скрытые члены и синтаксис Геттер/Сеттер (получатель/установщик значений)
По умолчанию члены класса являются открытыми для внешнего доступа (публичными). Используйте модификатор private
, чтобы скрыть их от внешнего доступа.
class Point {
private var _x = 0
private var _y = 0
private val bound = 100
def x: Int = _x
def x_=(newValue: Int): Unit = {
if (newValue < bound)
_x = newValue
else
printWarning()
}
def y: Int = _y
def y_=(newValue: Int): Unit = {
if (newValue < bound)
_y = newValue
else
printWarning()
}
private def printWarning(): Unit =
println("WARNING: Out of bounds")
}
val point1 = new Point
point1.x = 99
point1.y = 101 // выводит предупреждение (printWarning)
class Point:
private var _x = 0
private var _y = 0
private val bound = 100
def x: Int = _x
def x_=(newValue: Int): Unit =
if newValue < bound then
_x = newValue
else
printWarning()
def y: Int = _y
def y_=(newValue: Int): Unit =
if newValue < bound then
_y = newValue
else
printWarning()
private def printWarning(): Unit =
println("WARNING: Out of bounds")
end Point
val point1 = Point()
point1.x = 99
point1.y = 101 // выводит предупреждение (printWarning)
В данной версии класса Point
данные хранятся в скрытых переменных _x
и _y
. Существуют методы def x
и def y
для доступа к скрытым данным. Методы def x_=
и def y_=
(сеттеры) предназначены для проверки и установки значения _x
и _y
. Обратите внимание на специальный синтаксис для сеттеров: метод _=
применяется к имени геттера.
Первичные параметры конструктора с параметрами val
и var
являются общедоступными. Однако, поскольку val
- это константа, то нельзя писать следующее.
class Point(val x: Int, val y: Int)
val point = new Point(1, 2)
point.x = 3 // <-- не компилируется
class Point(val x: Int, val y: Int)
val point = Point(1, 2)
point.x = 3 // <-- не компилируется
Параметры без val
или var
являются скрытыми от внешнего доступа и видимы только внутри класса.
class Point(x: Int, y: Int)
val point = new Point(1, 2)
point.x // <-- не компилируется
class Point(x: Int, y: Int)
val point = Point(1, 2)
point.x // <-- не компилируется
Дополнительные ресурсы
- Узнайте больше о классах в Scala Book
- Как использовать вспомогательные конструкторы классов
Contributors to this page:
Contents
- Введение
- Основы
- Единобразие типов
- Классы
- Значения Параметров По умолчанию
- Именованные Аргументы
- Трейты
- Кортежи
- Композиция классов с трейтами
- Функции Высшего Порядка
- Вложенные Методы
- Множественные списки параметров (Каррирование)
- Классы Образцы
- Сопоставление с примером
- Объекты Одиночки
- Регулярные Выражения
- Объект Экстрактор
- Сложные for-выражения
- Обобщенные Классы
- Вариантность
- Верхнее Ограничение Типа
- Нижнее Ограничение Типа
- Внутренние классы
- Члены Абстрактного Типа
- Составные Типы
- Самоописываемые типы
- Контекстные параметры, также известные, как неявные параметры
- Неявные Преобразования
- Полиморфные методы
- Выведение Типа
- Операторы
- Вызов по имени
- Аннотации
- Пакеты и Импорт
- Объекты Пакета