추출자 오브젝트

스칼라에선 캐이스 클래스와 상관 없이 패턴을 정의할 수 있다. 이런 측면에서 추출자라 불리는 unapply라는 이름의 메소드를 정의한다. 예를 들어, 다음의 코드는 추출자 오브젝트 Twice를 정의한다.

object Twice {
  def apply(x: Int): Int = x * 2
  def unapply(z: Int): Option[Int] = if (z%2 == 0) Some(z/2) else None
}

object TwiceTest extends App {
  val x = Twice(21)
  x match { case Twice(n) => Console.println(n) } // prints 21
}

여기선 두 가지 구문적 컨벤션을 사용했다.

패턴 case Twice(n)Twice.unapply를 호출하는데, 이는 짝수와의 매칭에 사용된다. unapply의 반환 값은 인수가 매칭됐는지 여부와 다른 하위 값을 더 매칭해 나가야 할지를 알려준다. 여기선 하위 값이 z/2이다.

apply 메소드는 패턴 매칭에 필수 요소가 아니며, 단지 생성자를 흉내내기 위해 사용된다. val x = Twice(21)val x = Twice.apply(21)로 확장된다.

unapply의 반환 값은 반드시 다음 중에서 선택해야 한다.

  • 단순한 테스트라면 Boolean을 반환한다. case even()이 한 예다.
  • 타입 T의 단일 하위 값을 반환한다면, Option[T]를 반환한다.
  • 여러 하위 값 T1,...,Tn를 반환하고 싶다면, 이를 Option[(T1,...,Tn)]과 같이 튜플로 묶어준다.

때론 하위 값의 개수가 미리 고정돼 시퀀스를 반환하고 싶을 때도 있다. 이런 이유로 unapplySeq를 통해 패턴을 정의할 수 있다. 마지막 하위 값의 타입 Tn은 반드시 Seq[S]여야 한다. 이 기법은 case List(x1, ..., xn)과 같은 패턴에 사용된다.

추출자는 코드의 유지 관리성을 향상시켜준다. 더욱 자세한 내용은 Emir, Odersky, Willians의 “패턴을 통한 오브젝트의 매칭”(2007년 1월) 4장을 읽어보도록 하자.

윤창석, 이한욱 옮김