(1) enum class
| enum class Color { |
| RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET |
| } |
- Kotlin에서 enum은 소프트 키워드라 부르는 존재이다. 이는 Java에서 보다 더 많은 키워드를 써야 한다.
- 자바와 달리 값을 열거만 하는 것이 아닌, enum class안에 프로퍼티나 메서드를 정의할 수 있다.
| enum class Color(val r: Int, val g: Int, val b: Int) { |
| RED(255, 0, 0), |
| ORAGNE(255, 165, 0), |
| YELLOW(255, 255, 0), |
| GREEN(0, 255, 0), |
| BLUE(0, 0, 255), |
| INDIGO(75, 0, 130), |
| VIOLET(238, 130, 238); |
| |
| fun rgb() = (r * 256 + g) * 256 + b |
| } |
(2) when으로 enum class 다루기
| fun getMnemonic(color: Color) = |
| when (color) { |
| Color.RED, Color.ORANGE, Color.YELLOW -> "Warm" |
| Color.GREEN -> "Netural" |
| Color.BLUE, Color.INDIGO, Color.VIOLET -> "Cold" |
| } |
- Java와 달리 각 분기에 끝에 Break를 넣지 않아도 오류가 생기지 않음
- 한 분기 안에서 여러 적으로 매치 패턴을 사용할 때는 , 를 사용하여 분리
- 상수 값을 임포트 하면 해당 코드를 더 간단하게 만들 수 있음.
| import ch02.colors.Color |
| import ch02.colors.Color.* |
| |
| fun getMnemonic(color: Color) = |
| when (color) { |
| RED, ORANGE, YELLOW -> "Warm" |
| GREEN -> "Netural" |
| BLUE, INDIGO, VIOLET -> "Cold" |
| } |
(3) when과 임의의 객체 함께 사용
| fun mix(c1: Color, c2: Color) = when(setOf(c1, c2)) { |
| setOf(RED, YELLOW) -> ORANGE |
| setOf(YELLOW, BLUE) -> GREEN |
| setOf(BLUE, VIOLET) -> INDIGO |
| else -> throw Exception("Dirty Color") |
| } |
println(mix(BLUE, YELLOW))
- Java의 switch와 달리, Kotlin의 when은 임의의 객체를 허용한다.
- 인자로 전달받은 여러 객체를 그 객체들을 포함하는 집합인 Set 객체로 만드는 setOf 함수가 존재함. 이는 순서는 상관없음
(4) 인자 없는 when 사용
| fun mix(c1: Color, c2: Color) = |
| when { |
| (c1 == RED && c2 == YELLOW) || (c1 == YELLOW && c2 == RED) -> ORANGE |
| (c1 == YELLOW && c2 == BLUE) || (c1 == BLUE && c2 == YELLOW) -> GREEN |
| (c1 == BLUE && c2 == VIOLET) || (c1 == VIOLET && c2 == BLUE) -> INDIGO |
| |
| else -> throw Exception("더러운 색깔") |
| } |
- 임의의 객체와 함께 when을 사용하는 경우, 호출될 때마다 주어진 두 색이 when의 분기 조건에 있는 다른 두 색과 같은지 비교하기 위해서 여러 set 인스턴스를 생성하기 때문에 비효율적임
- when에 아무 인자가 없다면 각 분기의 조건이 Boolean 결과를 계산하는 식이어야 함.
(5) 스마트 캐스트
| interface Expr |
| class Num(val value: Int): Expr |
| class Sum(val left: Expr, val right.Expr): Expr |
| fun eval(e: Expr): Int { |
| if(e is Num) { |
| val n = e as Num |
| return n.value |
| } |
| if(e is Sum) { |
| return eval(e.right) + eval(e.left) |
| } |
| throw IllegalArgumentException("Unknown Expression") |
| } |
println(eval(Sum(Sum(Num(1), Num(2)), Num(4))))
- Kotlin에서 is를 이용하여 변수 타입을 검사하고 나면 컴파일러가 원하는 변수 타입으로 캐스팅 해준다.
- 클래스의 프로퍼티에서 스마트캐스트를 사용한다면 그 프로퍼티는 반드시 val 이어야 하며, 커스텀 접근자를 사용할 수 없다.
- 원하는 타입으로 명시적으로 타입 캐스팅을 해주기 위해서는 as 키워드를 사용한다.
(6) if를 when으로 변경 [Refactoring]
| fun eval(e: Expt): Int = |
| when(e) { |
| is Num -> e.value |
| is Sum -> eval(e.right) + eval(e.left) |
| else -> throw IllegalArgumentException("Unknown Expression") |
| } |
- when 식은 동등성 검사가 아닌 받은 값의 타입을 검사하는 역할로도 사용할 수 있다.
- 이는 타입을 검사하고 나면 바로 스마트 캐스팅이 이뤄지며, 따라서 Num이나 Sum의 멤버에 접근할 때 캐스팅이 필요없다.
(7) if와 when의 분기에서 블록 사용
| fun evalWithLogging(e: Expr): Int { |
| return when (e) { |
| is Num -> { |
| println("num: ${e.value}") |
| e.value |
| } |
| is Sum -> { |
| val left = evalWithLogging(e.left) |
| val right = evalWithLogging(e.right) |
| println("sum: $left + $right") |
| left + right |
| } |
| else -> throw IllegalArgumentException("Unknown Expression") |
| } |
| } |
- eval 함수에 로그를 추가시키고 싶다면 각 분기를 블록으로 만들고, 블록의 맨 마지막에 분기의 결과 값을 위치시키면 된다.