인터페이스와 필드를 클래스 사이에서 공유할 때 사용

자바8의 인터페이스와 유사한다. 클래스와 오브젝트는 트레이트를 확장하고 상속받을수 있으나, 트레이트는 인스턴스화 될 수 없으므로 파라미터가 없다.

Defining a Trait

키워드 tratit 사용하고 지시자 사용

trait HairColor

generic 타입와 추상화 메소드를 같이 사용하면 유용하게 쓰일수 있다.

trait Iterator[A] {
  def hasNext: Boolean
  def next(): A
}

trait Iterator[A]:
  def hasNext: Boolean
  def next(): A

→ generic type이 [A] 이다.

→ 트레이트를 확장하려면 A타입을 구체화해야하고 메소드를 선언해야 한다.

Using Traits

extends 키워드로 트레이드를 확장해서 쓸수있으며 abstract멤버를 사용할 때는 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()  // returns 0
iterator.next()  // returns 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()  // returns 0
iterator.next()  // returns 1

트레이트 이터레이터를 확장해서 클래스에서 사용하고 있는 예시가 포인트이다.

Subtyping

트레이트가 필요한 상황이라면, 트레이트의 하위 타입도 대신 쓸수 있다.

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))  // Prints 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))  // Prints Harry Sally

val animals = ArrayBuffer.empty[Pet] → 이게 핵심이다.