본문 바로가기
개발/코틀린(kotlin)

[Kotlin] 코틀린 기초 #2 enum, when

by darksilber 2020. 1. 28.
반응형

출처 - https://tourspace.tistory.com/99?category=797357

 

 

2.3 enum 과 when

2.3.1 enum

enum은 아래와 같이 사용합니다.

enum class Color { 
	RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET 
}

물론 이건 기본적인 형태이지만, 흔히 java에서 사용할때 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) { 
	println(Color.BLUE.rgb()) 
}

num 내부에 값과 함수까지 정의했습니다.

코틀린에서는 ; 를 사용하지 않지만 enum의 마지막에는 꼭 사용해야합니다. 

 

2.3.2 when에 enum을 사용

when은 자바와 다르게 좀더 확장성 있게 object를 지원합니다.

enum은 java에서도 지원하고, 당연히 kotlin에서 지원합니다.

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) { 
	println(getMnemonic(Color.BLUE)) 
}

when의 특징은 break;를 넣지 않아도 된다는 점입니다.

따라서 break를 빼먹어서 생기는 오류를 막을 수 있습니다.

만약에 여러값을 하나의 분기로 처리하고자 한다면 콤마 "," 를 사용하면 됩니다.

fun getWarmth(color: Color) = when(color) { 
	Color.RED, Color.ORANGE, Color.YELLOW -> "warm" 
    Color.GREEN -> "neutral" 
    Color.BLUE, Color.INDIGO, Color.VIOLET -> "cold" 
}

2.3.3 when의 인자로 object 사용

when은 object를 인자로 받을수 있기 때문에 아래와 같은 활용도 가능합니다.

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) { 
	println(mix(BLUE, YELLOW)) 
}

setOf는 java로 얘기하면 set을 만드는 함수 입니다.

(HashSet으로 생각하시면 편하겠네요~)

 

c1과 c2에 들어오는 순서는 상관이 없습니다.

예를들어 mix(RED, YELLOW) 와 mix(YELLOW, RED) 는 둘다 ORANGE가 반환됩니다.

 

또한 else를 사용하여 남은 처리를 할수도 있습니다.

 

이렇게 when을 사용하면 if ~ else, switch를 대체하여 좀더 간결하고 직관적인 코드를 작성할 수 있습니다.

 

2.3.4 인자없는 when

위 경우에는 전부 when에 인자값을 넣어서 사용했으나, 인자값 없이도 사용할 수 있습니다.

단! when에 인자가 없다면, 조건부분은 반드시 Boolean을 반환하는 expression이어야 합니다.

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) { 
	println(mixOptimized(BLUE, YELLOW)) 
}

 

setof를 빼면서 불필요 객체 생성은 막았지만, 왠지 복잡해 보이는군요.

이전 코드가 가독성은 더 좋아 보입니다.^^a


2.3.5 스마트 캐스트 (smart cast)

코틀린의 장점중 하나는 스마트 캐스트를 지원한다는 점입니다.

스마트 캐스트란 object의 타입 확인과 변환을 한번에 해주는 기능입니다.

interface Expr // 아무 함수도 없는 Dummy interface를 만든다. 

class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr

fun eval(e: Expr): Int { 
	if (e is Num) { // smart cast가 발생한다. 
    	val n = e as Num // e를 Num type으로 전환하지만, 이미 smart cast되어 Num 타입이다. (생략가능 라인)
        return n.value 
    }
    if (e is Sum) { // smart cast가 발생한다. 
    // 이미 e는 Sum type으로 변환된 상태이다 -> as를 이용하여 변환할 필요가 없다. 
    return eval(e.right) + eval(e.left) // 따라서 sum의 property인 right, left에 바로 접근할 수 있다. 
    }
    throw IllegalArgumentException("Unknown expression") 
}

fun main(args: Array) { 
	println(eval(Sum(Sum(Num(1), Num(2)), Num(4)))) 
}

위 예제를 보면 Num Sum은 모두 Expr 이라는 interface를 구현하고 있습니다.

is  instanceof와 같은 역할이라고 보면 되며 as는 강제 캐스팅이라고 보면 됩니다.

 

위에서 if (e is Num) 을 통과하여 내부 블럭으로 들어왔다면 e as Num 을 해줄 필요가 없습니다.

사실 이미 내부 블럭에서 e는 컴파일러에 의해 Num으로 이미 자동 캐스팅된 상태입니다.

 

 

이 코드를 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")
    }

 

if를 써도 되지만 when을 쓰는게 좀더 간결합니다.

 

2.3.7 if문과 when에서의 블럭사용

if문과 when문은 블럭을 사용해서 표현할 수 도 있습니다.

이때 마지막 문장이 블럭 전체의 결과값이 됩니다!!

 

fun evalWithLogging(e: Expr): Int = 
	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")
}

 

반응형

댓글