Трейты (Traits) используются, чтобы обмениваться между классами информацией о структуре и полях. Они похожи на интерфейсы из Java 8. Классы и объекты могут расширять трейты, но трейты не могут быть созданы и поэтому не имеют параметров.
Объявление трейта
Минимальное объявление трейта - это просто ключевое слово trait
и его имя:
trait HairColor
Трейты наиболее полезны в качестве обобщенного типа с абстрактными методами.
trait Iterator[A] {
def hasNext: Boolean
def next(): A
}
trait Iterator[A]:
def hasNext: Boolean
def next(): A
При наследовании от трейта Iterator[A]
требует указание типа A
а также реализация методов hasNext
и next
.
Использование трейтов
Чтобы использовать трейты, необходимо наследовать класс от него, используя ключевое слово extends
. Затем необходимо реализовать все абстрактные члены трейта, используя ключевое слово override
:
trait Iterator[A] {
def hasNext: Boolean
def next(): A
}
class IntIterator(to: Int) extends Iterator[Int] {
private var current = 0
override def hasNext: Boolean = current < to
override def next(): Int = {
if (hasNext) {
val t = current
current += 1
t
} else 0
}
}
val iterator = new IntIterator(10)
iterator.next() // вернет 0
iterator.next() // вернет 1
trait Iterator[A]:
def hasNext: Boolean
def next(): A
class IntIterator(to: Int) extends Iterator[Int]:
private var current = 0
override def hasNext: Boolean = current < to
override def next(): Int =
if hasNext then
val t = current
current += 1
t
else
0
end IntIterator
val iterator = new IntIterator(10)
iterator.next() // вернет 0
iterator.next() // вернет 1
Этот класс IntIterator
использует параметр to
в качестве верхней границы. Он наследуется от Iterator[Int]
, что означает, что метод next
должен возвращать Int.
Подтипы
Туда, где требуется определенный тип трейта, мы можем передавать любой наследованный от требуемого трейта класс
import scala.collection.mutable.ArrayBuffer
trait Pet {
val name: String
}
class Cat(val name: String) extends Pet
class Dog(val name: String) extends Pet
val dog = new Dog("Harry")
val cat = new Cat("Sally")
val animals = ArrayBuffer.empty[Pet]
animals.append(dog)
animals.append(cat)
animals.foreach(pet => println(pet.name)) // выведет "Harry" и "Sally"
import scala.collection.mutable.ArrayBuffer
trait Pet:
val name: String
class Cat(val name: String) extends Pet
class Dog(val name: String) extends Pet
val dog = Dog("Harry")
val cat = Cat("Sally")
val animals = ArrayBuffer.empty[Pet]
animals.append(dog)
animals.append(cat)
animals.foreach(pet => println(pet.name)) // выведет "Harry" и "Sally"
У трейта Pet
есть абстрактное поле name
, которое реализовано в классах Cat
and Dog
. В последней строке мы вызываем pet.name
, который должен быть реализован в любом подтипе, унаследованном от трейта Pet
.
Дополнительные ресурсы
- Узнайте больше о трейтах в Scala Book
- Использование трейтов для определения Enum
Contributors to this page:
Contents
- Введение
- Основы
- Единобразие типов
- Классы
- Значения Параметров По умолчанию
- Именованные Аргументы
- Трейты
- Кортежи
- Композиция классов с трейтами
- Функции Высшего Порядка
- Вложенные Методы
- Множественные списки параметров (Каррирование)
- Классы Образцы
- Сопоставление с примером
- Объекты Одиночки
- Регулярные Выражения
- Объект Экстрактор
- Сложные for-выражения
- Обобщенные Классы
- Вариантность
- Верхнее Ограничение Типа
- Нижнее Ограничение Типа
- Внутренние классы
- Члены Абстрактного Типа
- Составные Типы
- Самоописываемые типы
- Контекстные параметры, также известные, как неявные параметры
- Неявные Преобразования
- Полиморфные методы
- Выведение Типа
- Операторы
- Вызов по имени
- Аннотации
- Пакеты и Импорт
- Объекты Пакета