When

Panda·2022년 3월 5일
0

Kotlin

목록 보기
6/10

코틀린 기능인 When에 대하여 공부하였습니다.

코틀린은 자바에 존재하는 Switch가 없는대신에
그와 거의 비슷한 When을 지원을 하고 있습니다.

기본적인 문법

fun main() {
    val num = readlnOrNull()?.toIntOrNull()

    // 스마트 캐스트 is로 검사하게 되면
    when(num) {
        1 -> println("1를 입력받았습니다!")
        2 -> println("2를 입력받았습니다!")
        3, 4 -> println("3 또는 4를 입력받았습니다!")
        in 5..10 -> println("5와 10 사이에 숫자를 입력받았습니다!")
        else -> println("예외적인 숫자 입력!")
    }
}

기본적인 문법을 살펴보자면

  1. 특정 값으로 조건 걸기
  2. 여러가지 값으로 조건을 걸기
  3. 범위로 조건을 걸기
  4. else 구문

쓰고나서 느낀점은 switch와 다르게 break문을 일일이 추가를 안해도된다는 점이
정말 편리하였고 또 다양한 표현식으로 조건을 표시할수 있는게 편했던 것 같습니다.

여기까지만 알아도 잘 쓸수 있지만
좀더 심화과정으로 들어가보겠습니다.

스마트 캐스트

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

fun main() {
	fun eval(e : Expr) : Int =
    	    when(e) {
        	    is Num -> e.value
            	is Sum -> eval(e.left) + eval(e.right)
            	else -> throw java.lang.IllegalArgumentException("Unknown")
	        }
            
    println(eval(Sum(Sum(Num(1), Num(2)), Num(5))))
}

- 결과 -
8

when의 특성이라기 보다는 is의 특성인데
is를 사용함으로써 스마트 캐스팅이 되어 변수쓰듯이 사용을 할수 있게 됩니다.

인자가 없는 When

fun main() {
    val num = readlnOrNull()?.toIntOrNull()

	//when에 아무 인자도 없다.
    num?.let {
        when {
            (it >= 90) -> println("A")
            (80 <= it && it < 90) -> println("B")
            (70 <= it && it < 80) -> println("C")
            else -> println("F")
        }
    }
}

놀라웠던 사실이였는데 when에는 인자가 없어도 작동이 된다는 사실이였습니다.
보시면 인자가 없는데도 불구하고 조건식으로 수행을 하는것을 볼 수가 있습니다.

하지만 그냥 if문 쓰는거랑 별 다를 것 없는 형태이기 때문에
이렇게 굳이 쓸 이유는 없을 것 같습니다.

Class를 활용한 When

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); // need semicolon

    fun rgb() = (r * 256 + g) * 256 + b
}

fun main() {
	when(Color.BLUE) {
        Color.RED -> println("Richard")
        Color.ORANGE -> println("Of")
        Color.YELLOW -> println("York")
        Color.GREEN -> println("Gave")
        Color.BLUE -> println("Battle")
        Color.INDIGO -> println("In")
        Color.VIOLET -> println("Vain")
    }
}

클래스를 활용을 하여 when을 이런 형태로 구현할 수 있는데
정말 가독성 있는 코드라고 생각이 되는 부분이였습니다.

특정한 상태(값)가 특정 기능을 수행하는 것을 직관적으로 확인 할수 있어서 되게 좋은 방식 같습니다.

seales class 활용

sealed class FontColor {
    object Red : FontColor()
    object Green : FontColor()
    object Blue : FontColor()
}

fun main() {
	val fontColor : FontColor = FontColor.Red
    
    // 기본적으로는 warning으로 표시되지만 progressiveMode 값을 True로 설정하면 오류 발생합니당
    when(fontColor) {
        FontColor.Red -> println("Noto Sans")
        FontColor.Green -> println("Open Sans")
        // 에러 발생 : 경고 혹은 컴파일 에러 발생
    }
}

코드를 작성하다보면 어떠한 인터페이스들을 확장시키는 경우가 빈번히 존재합니다.
만약 내가 when으로 인터페이스에 각각 해당하는 기능들을 구현을 해뒀는데
인터페이스를 확장해야 될 상황이 발생하고 인터페이스에 대해서만 확장을 시키고
실제 구현하는 when 부분은 실수로 구현을 못했다고 가정하면 크나큰 문제이기 때문에
이러한 문제를 해결할 수 있는 방법을 알아보겠습니다.

바로 sealed class의 활용입니다.
sealed class란?

  • 추상 클래스
  • 생성자는 private이고 public으로 설정 불가능
  • 하위 클래스는 class, data class, object class으로 정의할 수 있음

중첩클래스의 형태로 구현을 하였는데
sealed class를 사용하면 컴파일 시점에 하위 클래스들이 정의되어 있기 때문에
모든 하위 클래스에 대해서 구현하면 else를 추가 안해도 됩니다.

또한 sealed class를 확장하게 되면(내부 클래스 추가) when 구문에서 에러가 발생하게 됩니다. 하지만 제 IDE는 경고 문구만 보여주고 있는데
기본적으로는 경고 문구 이나 progressiveMode를 true로 설정하면 에러가 발생한다고 합니다.

따라서 인터페이스만 확장하게 되면 구현부인 when에서 경고 혹은 에러가 발생하기 때문에
개발자의 실수를 방지 할수 있습니다.

느낀 점

when에 대해서 알아봤는데
기초적인 사용법은 간단했지만

실제로 사용하게 되면 class를 활용하여 사용을 해 생각할 거리가 많을 것 같습니다.

profile
실력있는 개발자가 되보자!

0개의 댓글

관련 채용 정보