2.3 선택 표현과 처리: enum과 when
when 은 자바의 switch를 대치하되 훨씬 더 강력하며, 앞으로 더 자주 사용할 프로그래밍 요소이다.
2.3.1 enum 클래스 정의
enum class Color{
RED, ORAGNE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
}
코틀린에서 enum은 소프트 키워드(soft keyword)라 부르는 존재다. 반면 class는 키워드다. enum은 특별한 의미를 지니지만 다른 곳에서 사용할 수 있는 반면, class라는 이름은 다른곳에서 사용할 수 없다.
자바의 마찬가지로 enum 클래스 안에도 프로퍼티나 메소드를 정의할 수 있다.
enum class Color(val r: Int, val g: Int, val b: Int){
// 각 상수를 생성할 때 그에 대한 프로퍼티 값을 지정한다.
RED(255, 0, 0), ORAGNE(255, 165, 0), YELLOW(255. 255. 0), .... VIOLET(238, 130 ,238);
fun rgb() = (r * 256 + g) * 256 + b // enum 클래스 안에서 메소드를 정의한다.
}
>>> println(Color.BLUE.rgb())
2.3.2 when으로 enum 클래스 다루기
fun getMnemonic(color: Color) = // 함수의 반환값으로 when 식을 직접 사용
when (color) {
Color.RED -> "Richard"
Color.ORANGE -> "Of"
...
Color.VIOLET -> "Vain"
}
>> println(getMnemonic(Color.BLUE))
Battle
한 when 분기 안에 여러 값 사용하기
fun getWarmth(color: Color) = // 함수의 반환값으로 when 식을 직접 사용
when (color) {
Color.RED, Color.ORANGE, Color.YELLOW -> "warm"
Color.GREEN -> "neutral"
...
}
>> println(getWarmth(Color.ORANGE))
warm
상수 값을 임포트하면 코드를 더 간단하게 만들 수 있다.
import ch2.colors.Color // 다른 패키지에서 정의한 Color 클래스를 임포트 한다.
import ch2.colors.Color.* // 짧은 이름으로 사용하기 위해 enum 상수를 모두 임포트 한다.
fun getWarmth(color: Color) = // 함수의 반환값으로 when 식을 직접 사용
when (color) {
RED, ORANGE, YELLOW -> "warm"
GREEN -> "neutral"
...
}
>> println(getWarmth(Color.ORANGE))
warm
2.3.3 when과 임의의 객체를 함께 사용
분기 조건에 상수(enum 상수나 숫자 리터럴)만을 사용할 수 있는 자바 switch와 달리 코틀린 when의 분기 조건은 임의의 객체를 허용한다.
두 색을 혼합한 색을 반환하는 함수를 작성하자.
fun mix(c1: Color, c2: Color) =
when (setOf(c1, c2)){ // when 식의 인자로 아무 객체나 사용할 수 있다.
setOf(RED, YELLOW) -> ORANGE,
setOf(YELLOW, BLUE) -> GREEN,
...
else -> throw Exception("Dirty Color") // 매치되는 분기 조건이 없으면 이 문장 실행
}
이를 구현하기 위해 집합 비교 를 사용한다.
코틀린 표준 라이브러리에는 인자로 전달받은 여러 객체를 그 객체들을 포함하는 집합인 Set 객체로 만드는 setOf라는 함수가 있다. 객체 사이를 매치할 때 동등성(equality)을 사용한다.
2.3.4 인자 없는 when 사용
앞의 예제는 setOf 함수를 사용하여 Set 인스턴스를 계속 생성한다. 그렇기 때문에 많이 호출된다면 불필요한 가바지 객체가 늘어난다. 이럴때 인자가 없는 when 식을 사용하면 불필요한 객체 생성을 막을 수 있다. 단 코드가 약간 읽기 어려워 진다.. 성능 향상을 위해 이정도 비용은 감수해야 하는 ..
fun minxOptimized(c1: Color, c2: Color) =
when {
(c1 == RED && c2 == YELLOW) || (c1 == YELLOW && c2 == RED) -> ORANGE
(c1 == YELLOW && c2 == BLUE) || (c1 == BLUE && c2 ==YELLOW) -> GREEN
...
else -> throw Exception("Dirty color")
}
when에 아무 인자도 없으려면 각 분기의 조건이 불리언 결과를 계산하는 식이어야 한다.
2.3.5 스마트 캐스트 : 타입 검사와 타입 캐스트를 조합
(1 + 2) + 4 와 같은 간단한 산술식을 계산하는 함수를 만들어 보자.
Num은 항상 말단(leaf) 노드이며, Sum은 자식이 둘 있는 중간(non-terminal)노드이다. Sum 노드의 두 자식은 덧셈의 두 인자다.
Expr 인터페이스를 선언해보자. 클래스가 구현하는 인터페이스를 지정하기 위해서 콜론(:) 뒤에 인터페이스 이름을 사용한다.
Expr은 아무 메소드도 선언하지 않으며, 단지 여러 타입의 식 객체를 아우르는 공통 타입 역할만 수행한다.
interface Expr
class Num(val value: Int) : Expr // value라는 프로퍼티만 존재하는 단순한 클래스로 Expr 인터페이스를 구현
class Sum(val left: Expr, val right: Expr) Expr // Expr 타입의 객체라면 어떤 것이나 Sum의 연산의 인자가 될 수 있다. 따라서 Num이나 다른 Sum이 인자로 올 수 있다.
>> println (eval(Sum(Sum(Num(1), Num(2)), Num(4)))
7
Expr 인터페이스에는 두 가지 구현 클래스가 존재한다. 따라서 식을 평가하려면 두 가지 경우를 고려해야 한다.
- 어떤 식이 수라면 그 값을 반환한다.
- 어떤 식이 합계라면 좌항과 우항의 값을 계산한 다음에 그 두 값을 합한 값을 반환한다.
코틀린에서 if 문을 사용하여 자바 스타일로 함수를 작성해보기
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) // 변수 e에 대해 스마트 캐스트를 사용
}
throw IllegalArgumentException("Unknown expression")
}
코틀린의 is 는 자바의 instanceof와 비슷하다. 자바에서는 instanceOf로 확인한 다음에 그 타입에 속한 멤버에 접근하기 위해서는 명시적으로 변수 타입을 캐스팅해야 한다. 코틀린에서는 프로그래머 대신 컴파일러가 캐스팅을 해준다. is로 검사하고 나면 컴파일러가 캐스팅을 수행해주는데 이를 스마트 캐스트(smart cast)라고 부른다.
2.3.6 리팩토링: if를 when으로 변경
if식을 본문으로 사용해 더 간단한 메소드를 만들 수 있다.
fun eval(e: Expr): Int =
if(e is Num){
e.value
}else if(e is Sum){
eval(e.right) + eval(e.left)
}else{
throw IllegalArgumentException("Unknown expression")
}
>>> println(eval(Sum(Num(1), Num(2)))
3
when을 사용해서 더 다듬을 수 있다.
fun eval(e: Expr): Int =
when(e){
is Num -> e.value
is Sum -> eval(e.right) + eval(e.left)
else -> throw IllegalArgumentException("Unknown expression")
}
'프로그래밍 노트 > Kotlin' 카테고리의 다른 글
[Kotlin] 코틀린(Kotlin)에서 컬렉션 만들기 (0) | 2020.11.14 |
---|---|
[Kotlin] 코틀린(Kotlin) while과 for 루프 (0) | 2020.11.09 |
[Kotlin] 코틀린(Kotlin) 클래스와 프로퍼티 (0) | 2020.11.09 |
[Kotlin] 코틀린(Kotlin) 기본요소 (함수와 변수) (0) | 2020.11.07 |
코틀린(Kotlin)이란 무엇이며 왜 필요한가 (0) | 2020.11.05 |