Tour of Scala

Трейты

Language

Трейты (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: