Skip to content

15장 case classes and pattern matching

kingori edited this page Nov 19, 2011 · 12 revisions

패턴매칭할 클래스에 case키워드를 사용한다.

15.1 A simple example

zeide

간단한 예제로 알아보자.

scala> abstract class Expr
defined class Expr
scala>   case class Var(name: String) extends Expr
defined class Var
scala>   case class Number(num: Double) extends Expr
defined class Number
scala>   case class UnOp(operator: String, arg: Expr) extends Expr
defined class UnOp
scala>   case class BinOp(operator: String,
     |       left: Expr, right: Expr) extends Expr
defined class BinOp

case classes modifier가 주는 문법적 편리함

  • 클래스명으로 팩토리메소드 추가할 수 있다.
  • case 클래스의 파라미터 리스트에 있는 인자들은 모두 val
  • toString, hashCode, equals 메소드의 "natural"구현 사용할 수 있다.
  • copy 메소드를 사용할 수 있다.
  • 패턴매칭을 지원한다.

kingori

  • pattern matching
    • selector match { alternatives }
    • switch와 다른 점
      • match도 expression이다. 즉, 값을 반환한다.
      • 명시적으로 break; 를 해야 하는 switch와 달리 match를 찾은 이후엔 계속 matching을 시도하지 않는다.
      • 어떤 패턴에도 매칭되지 않으면 MatchError 예외를 던진다. 예외를 피하려면 case _ => 를 명시하는 방법을 써야 한다.

15.2 Kinds of patterns

kingori

  • 패턴 유형
    • wildcard pattern: case _ => . 아무거나 다 대응됨. java switch의 default와 비슷.
    • constant pattern: 특정 값. 리터럴/ val / 싱글턴 객체 사용 가능함.
def describe(x: Any) = x match {
    case 5 => "five"
    case true => "truth"
    case "hello" => "hi!"
    case Nil => "the empty list"
    case _ => "something else"
}
  • variable pattern: 아무 객체에나 매칭. _와 달리 매칭된 variable을 활용할 수 있음
expr match {
  case 0 => "zero"
  case somethingElse => "not zero: "+ somethingElse
}
 * variable pattern과 constant를 구분하기 위해 소문자로 시작하는 이름은 pattern variable, 나머지는 상수로 취급.
    * 소문자 상수를 어쩔 수 없이 써야한다면? (그러나 이런 짓 하지 말자)
        * prefix with qualifier ex) Math.pi
        * back tick 사용 ex) \`pi\`
import math.{E,Pi}
val pi = math.Pi
E match {
  case Pi => "strange math? Pi = "+ Pi //상수 매칭
  case _ => "OK"
}
res0: java.lang.String = OK

E match {
  case pi => "strange math? Pi = "+ pi //변수 매칭
  //case _ => "OK" //syntax error: unreachable code
}
res1: java.lang.String = strange math? Pi = 2.718281828459045
  • constructor pattern: 생성자명(patterns)
    • pattern 안에 pattern을 쓸 수 있음: scala는 deep match를 지원함.
expr match {
  case BinOp("+", e, Number(0)) => println("a deep match")
  case _ =>
}
  • sequence pattern: List나 Array 류의 sequence type에 매칭.
expr match {
  case List(0, _, _) => println("found it")
  case _ =>
}

expr match {
  case List(0, _*) => println("found it")
  case _ =>
}
  • tuple pattern: tuple에 매칭.
expr match {
  case (a, b, c) => println("matched "+ a + b + c)
  case _ =>
}
  • typed pattern: 타입에 매칭
def generalSize(x: Any) = x match {
  case s: String => s.length //matches every non-null(!) instance of String. caution: as type of x is Any and type of s is String, you should use s to access member of String.
  case m: Map[_, _] => m.size
  case _ => 1
}

cf) poor java style. yuck!
if (x.isInstanceOf[String]) {
  val s = x.asInstanceOf[String]
  s.length
} else ...
 * 자바의 generic과 마찬가지로 type erasing이 존재함. 따라서 collection 내부의 type matching 등은 불가능함. 단, array는 예외임.
scala> def isIntIntMap(x: Any) = x match {  //does not work as expected
  case m: Map[Int, Int] => true
  case _ => false
}
warning: there were unchecked warnings; rerun with unchecked for details
isIntIntMap: (x: Any)Boolean

15.3 Pattern guards

15.4 Pattern overlaps

15.5 Sealed classes

15.6 The Option type

15.7 Patterns everywhere

15.8 A larger example

15.9 Conclusion

extractor는 chapter.26에서 만날 수 있습니다.

Clone this wiki locally