독서관련/Programming in Scala

Scala CH15. 케이스 클래스와 패턴 매치

ColinKang 2020. 3. 29. 13:19
아래의 글은 마틴 오더스키,렉스 스푼,빌 베너스 공저 / 오현석,이동욱,반영록 공역, 『Programming in Scala 3/e』,에이콘출판사(2017), CH01의 내용을 기반으로 작성하였습니다.

 

abstract class Expr

case class Var(name: String) extends Expr

case class Number(num: Double) extends Expr

case class UnOp(operator: String, arg: Expr) extends Expr

case class BinOp(operator: String, left: Expr, right: Expr) extends Expr

 

 

def simplifyTop(expr: Expr) : Expr = expr match {

    case UnOp("-", UnOp("=", e) => e

    case BinOp("+", e, Number(0)) => e

    case BinOp("*", e, Number(1)) => e

    case _ => expr

}

 

 

match는 자바의 switch와 비슷

스칼라의 매치는 표현식으로 그 식은 결과 값을 내놓는다.

스칼라 대안 표현식은 다음 케이스로 빠지지 않는다

매치에 실패하면 에러 발생

 

상수 패턴 : contant pattern

변수만을 사용한 패턴 : variable pattern

와일드카드 패턴 : wildcard pattern

생성자 패턴 : constructor pattern

 

와일드카드 패턴

(_)는 어떤 객체라도 매치할수 있다

 

expr match {

    case BinOp(op, left, right) =>

        println(expr + " is a binary operation")

    case _ => // 디폴트 처리

}

 

 

상수패턴

상수패턴은 자신과 똑같은 값과 매치된다.

 

 

def describe(x: Any) = x match {

    case 5 => "five"

    case true => "truth"

    case "hello" => "hi!"

    case Nil => "the empty list"

    case _ => "something else"

}

 

 

변수패턴

와일드 카드 처럼 어떤 객체와도 매칭된다.

와일드 카드와 다른 점은 변수에 객체를 바인딩한다.

 

 

expr match {

    case 0 => "zero"

    case somethingElse => "not zero: " + somethingElse

}

 

 

 

생성자패턴

BinOp("+", e, Number(0))인 형태로 이름 다음에 괄호로 둘러쌓인 여러 패턴인 "+", e, Number(0) 이 왔다.

인자로 전달받은 것이 괄호안의 패턴과 정확히 일치하는지 매치

 

 

expr match {

    case BinOp("+", e, Number(0)) => println("a deep match")

    case _ =>

}

 

 

시퀀스 패턴

expr match {

    case List(0, _, _) => println("found it")

    case _ =>

}

 

 

튜플 패턴

def tupleDemo(expr: Any) {

    expr match {

        case (a, b, c) => println("matched" + a + b + c)

        case _ =>

    }

}

 

 

타입지정 패턴

def generalSize(x: Any) = x match {

    case s: String => s.length

    case m: Map[_, _] => m.size

    case _ =>

}

 

어떤 표현이 string 타입인지

expr.isInstanceOf[String]

 

 

동일한 표현식을 문자열 타입으로 반환

expr.asInstanceOf[String]

 

 

타입소거의 유일한 예외는 배열임.

 

 

변수바인딩

변수가 하나만 있는 패턴 말고, 다른 패턴에 변수를 추가도 가능

expr match {

    case UnOp("abs", e @ UnOp("abs", _)) => e

    case _ =>

}

 

 

패턴 가드

패턴 뒤에 오고 if로 시작한다.

 

 

def simplifyAdd(e: Expr) = e match {

    case BinOp("+", x, y) if x == y => BinOp("+", x, Number)

    case _ =>

}

 

봉인된 클래스 : sealed case classed

match 마지막에 디폰트를 넣지만 이는 합리적인 디폴트 동작이 있을 때만이고, 

그런 동작이 없다면, 어떻게 하면 모든 가능성을 다 처리했다고 안심할까?

match 식에서 놓친 패턴 조합이 있다면 컴파일러에게 찾도록 도움 요청

 

케이스의 클래스의 슈퍼 클래스를 봉인된 케이스로 만드는 것

그 클래스와 같은 파일이 아닌 다른 곳에서 새로운 서브 클래스를 만들수 없다.

sealed abstracrt class Expr

 

Option 타입

있으면 Some(x) 형태로 값이 있고 없으면 None 반환

Option[String]

 

 

부분함수

val second: PartialFuncrtion[List[Int}, Int} = {

    case x :: y :: _ => y

}

 

 

new PartialFunctin[List[Int], Int] {

    def apply(xs: List[Int] = xs match {

        case x :: y :: _ => y

    }

    def isDefinedAt(xs: List[Int]) = xs match {

        case x :: y :: _ => true

        case _ => false

    }  

}

어떠한 리터럴의 타입이 PartialFunction이면 이 변환을 수행

하지만, Function이거나 타입 표기가 없으면 완전한 함수로 변환