코틀린의 when 은 자바의 switch를 대치하되 훨씬 더 강력하고 자주사용한다.
enum class Color{
RED,ORANGE,YELLOW,GREEN,BLUE,
}
enum 은 단순 값만 열거하는 존재가 아니라 프로퍼티나 메서드를 정의할 수 있다.
enum class Color(
val r: Int, val g: Int, val b: Int
) {
RED(255, 0, 0), ORANGE(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
}
fun main(args: Array<String>) {
println(Color.BLUE.rgb())
}
여기서 코틀린 중에서 유일하게 ; 를 사용하는 것을 볼 수 있다.
enum 클래스 안에 메서들르 정의하는 경우
반드시 enum 상수 목록과 메서드 정의 사이에 세미콜론을 넣어야한다.
enum class Color {
RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
}
fun getMnemonic(color: Color) =
when (color) {
Color.RED -> "Richard"
Color.ORANGE -> "Of"
Color.YELLOW -> "York"
Color.GREEN -> "Gave"
Color.BLUE -> "Battle"
Color.INDIGO -> "In"
Color.VIOLET -> "Vain"
}
fun main(args: Array<String>) {
println(getMnemonic(Color.BLUE))
}
자바와 다르게 break 를 안 넣어도 된다.
한 분기 안에 여러 값을 매치 패턴으로 사용할 수 있다. 이런 경우 , 를 이용해주면 된다.
enum class Color {
RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
}
fun getWarmth(color: Color) = when(color) {
Color.RED, Color.ORANGE, Color.YELLOW -> "warm"
Color.GREEN -> "neutral"
Color.BLUE, Color.INDIGO, Color.VIOLET -> "cold"
}
fun main(args: Array<String>) {
p
상수만 사용할 수 있는 자바의 switch와 달리 코틀린의 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")
}
fun main(args: Array<String>) {
println(mix(BLUE, YELLOW))
}
인자가 없으면 코드 읽기가 어려워지지만 성능을 더 향상시킨다.
fun mixOptimized(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("Dirty color")
}
fun main(args: Array<String>) {
println(mixOptimized(BLUE, YELLOW))
}
위의 코드에 when 에 아무 인자도 없다
=> Boolean 값으로 판단.
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 //1)
return n.value
}
if (e is Sum) {
return eval(e.right) + eval(e.left) //2)
}
throw IllegalArgumentException("Unknown expression")
}
fun main(args: Array<String>) {
println(eval(Sum(Sum(Num(1), Num(2)), Num(4))))
}
Sum 의 경우 좌우 인자에 대해서 left 와 right property로 저장한다.
Expr 인터페이스에는 두 가지 구현 클래스가 존재
따라서 식을 평가하려면 두 가지 경우를 고려해야한다.
1) 에서 Num으로 타입을 변환하는데 이는 불필요한 중복이다.
2)변수 e에 대해 스마트 캐스트를 사용한다.
스마트 캐스트는 값이 바뀔 수 없는 경우에만 작동!! => 해당 property에 대한 접근이 항상 같은 값을 내놓는다고 확인을 해야한다.
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")
}
fun main(args: Array<String>) {
println(eval(Sum(Num(1), Num(2))))
}
위의 코드를 when 을 이용해서 다듬어 보자.
fun eval(e: Expr): Int =
when (e) {
is Num -> //1)
e.value //2)
is Sum -> //1)
eval(e.right) + eval(e.left) //2)
else ->
throw IllegalArgumentException("Unknown expression")
}
fun main(args: Array<String>) {
println(eval(Sum(Num(1), Num(2))))
}
1) 인자 타입을 검사하는 when 분기들
2) 이부분에 스마트 캐스트가 쓰였다.
타입을 검사하고나면 스마트 캐스트가 이뤄진다
-> Num 이나 Sum의 멤버에 접근할 때 변수를 강제로 캐스팅할 필요가 없다.
fun evalWithLogging(e: Expr): Int =
when (e) {
is Num -> {
println("num: ${e.value}")
e.value //1)
}
is Sum -> {
val left = evalWithLogging(e.left)
val right = evalWithLogging(e.right)
println("sum: $left + $right")
left + right //2)
}
else -> throw IllegalArgumentException("Unknown expression")
}
fun main(args: Array<String>) {
println(evalWithLogging(Sum(Sum(Num(1), Num(2)), Num(4))))
}
1) 이 식이 블록의 마지막 식이므로 e의 타입이 Num 이면 e.value를 반환
2) e의 타입이 Sum 이면 이 식의 값이 반환된다.