enum 과 when

siwan·2021년 10월 28일
0

코틀린 기초

목록 보기
3/6

enum

간단하게 무지개색을 표현하는 enum class를 만들어보자

enum class Color{
  RED,ORANGE,YELLOW,GREEN,BLUE,INDIGO,VIOLET
}
  1. 자바에서는 enum 이지만 코틀린에서는 enum class 이다.
  2. 코틀린에서 enum은 소프트 키워드라 부르는 존재다
  3. 코틀린은 자바와 다르게 enum에 단순히 값만 열거하는 존재가 아니고 class 이기 때문에 프로퍼티나 메소드를 정의할 수 있다.
--- enum class 프로퍼티, 메소드 예제

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
}

println(Color.BLUE.rgb())
>>>255

enum class에 메소드를 정의 하는 경우 enum 상수목록과 메소드 사이에 세미콜론이 존재 하여야 한다.

when

  • 자바에서 switch case 문을 이용하지만 kotlin에서는 when절을 이용해 분기 처리가 가능하다.
  • if문과 마찬가지로 when절도 식으로 만들어 낼 수 있다
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
}

println(getMenemonic(Color.BLUE))
>>Battle

위 코드는 color로 전달된 값과 같은 분기를 찾는 코드이다.
1. when 은 자바와 달리 마지막 구문에 break를 넣지 않아도 된다.

----여러값을 매치 패턴으로 할 경우

fun getMnemonic(color:Color)=
when(color){
 Color.RED,Color.ORANGE,Color.YELLOW  ->"warm" // 여러값을 구분 할때 콤마(,)로 표시
 Color.GREEN -> "neutral"
 Color.BLUE,Color.INDIGO,Color.VIOLET -> "cold"
}

println(getMenemonic(Color.BLUE))
>>cold

한 분기 안에서 여러값을 매치 패턴으로 사용 할 수 있으며 콤마(,)로 분리한다.

  • when은 임의의 객체를 함께 사용 가능하다.
----setOf를 통한 임의의 객체

fun mix(c1:Color,c2:Color) = 
when(setOf(c1,c2)){
 setOf(RED,ORANGE)  ->ORANGE  
 setOf(YELLO,BLUE) -> GREEN
 setOf(BLUE,VIOLET) -> IDIGO
 else -> throw Exception("Dirty color")
}


println(mix(Color.RED,Color.ORANGE))
>> ORANGE

위 코드에서는 c1,c2 인자값을 받아 setOf(객체)를 통해 분기 처리를 하였다.
만약 위의 조건을 성립하지 않으면 else를 타서 exception을 타게 된다.

인자 없는 when 사용

  • 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("Dirty color")
}


println(mix(Color.BLUE,Color.YELLOW))
>> GREEN
  1. when에 아무 인자가 없으면 분기의 조건이 bool 결과를 계산하는 식이어야 한다.
  2. 추가객체를 만들지 않는다는 장점은 있지만 가독성이 떨어진다.

스마트 캐스트 : 타입 검사와 타입 캐스트를 조합

  • 간단한 산술식을 계산하는 함수를 만들어보자
interface Expr {
    class Num(val value: Int) : Expr // value 라는 프로퍼티만 존재하는 Num class
    class Sum(val left: Expr, val right: Expr) : Expr // Exper 타입의 객체라면 어떤 것이나 연산의 
    인자가 될 수 있다.
}

fun eval(e: Expr): Int {
    if (e is Expr.Num) {
        return e.value
    }
    if (e is Expr.Sum) {
        return eval(e.right) + eval(e.left)
    }
    throw IllegalArgumentException("Unknown expressions")
}

println(eval(Expr.Sum(Expr.Sum(Expr.Num(1),Expr.Num(2)),Expr.Num(4))))
>>> 7

스마트 캐스트
코틀린에서는 is를 사용해 변수타입을 검사한다. (자바에서는 instanceof)
자바에서는 instanceof로 확인한 타입에 속한 멤버를 접근하기 위해서는 명시적으로 변수 타입을 캐스팅 해야한다.
하지만 코틀린에서는 어떤 타입인지 is로 검사하고 나면 굳이 변수를 원하는 캐스팅하지 않아도 변수가 원하는 타입으로 선언된것 처럼 사용 할 수 있는 장점이 있고 이를 프로그래머 대신 컴파일러가 캐스팅을 해준다.

리팩토링 : if를 when으로 변경

fun eval(e: Expr): Int =
    when(e){
        is Expr.Num-> e.value
        is Expr.Sum -> eval(e.right) + eval(e.left)
        else -> throw IllegalArgumentException("Unknown expressions")
    }

when으로 분기마다 변수타입을 검사 한 후 반환값을 자동으로 스마트 캐스팅 해 줄 수 있다
가독성이 더 좋아보이는 장점이 있다.

if와 when을 분기에서 블록 사용

  fun evalWithLogging(e: Expr): Int =
    when (e) {
        is Expr.Num -> {
            println("num: ${e.value}") // 마지막 e.value 가 반환된다.
            e.value
        }
        is Expr.Sum -> {
            val left = evalWithLogging(e.left)
            val right = evalWithLogging(e.right)
            println("sum : $left + $right")
            left + right   //e의 타입이 sum이면 이 식이 반환된다.
        }
        else -> throw IllegalArgumentException("Unknown expressions")
    }
    
 println(evalWithLogging(Expr.Sum(Expr.Sum(Expr.Num(1), Expr.Num(2)), Expr.Num(4))))
 
 >>>
num: 1
num: 2
sum : 1+2
num: 4
sum : 3+4
7

when절을 식으로 이용 할 땐 블록의 마지막 결과값을 반환한다.

profile
station3 다방 안드로이드 개발자

0개의 댓글