728x90
반응형
✅ 선택 표현과 처리 : enum과 when
- when은 자바의 switch를 대치하되 훨씬 더 강력하며, 자주 사용하는 프로그래밍 요소
- when과 더불어 enum을 선언하는 방법과 스마트 캐스트에 대해 살펴봄
📌 enum 클래스 정의
// 간단한 enum 클래스 정의
enum class Color {
RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
}
- enum은 특정한 특징이나 속성으로 분류해서 사용하는 값들을 나열할 때 사용
- 코틀린에서는 enum class를 사용하지만 자바에서는 enum을 사용
- 코틀린에서 enum은 소프트 키워드라 부름
- enum 클래스 안에 프로퍼티나 메서드를 정의할 수 있으며, 상수를 정의할 때는 그 상수에 해당하는 프로퍼티 값을 지정해야 함
- enum 클래스 안에 메서드를 정의하는 경우 반드시 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
}
println(Color.BLUE.rgb()) // 255
📌 when으로 enum 클래스 다루기
- 자바의 switch문을 대신할 수 있는 코틀린의 구성 요소는 when
- 자바와 다르게 각 분기의 끝에 break를 넣지 않아도 됨
- 성공적으로 매치되는 분기를 찾으면 switch는 그 분기를 실행
- 한 분기 안에 여러 값을 매치 패턴으로 사용할 수 있으며, 그럴 경우 값 사이를 콤마(,)로 분리
// when을 사용해 올바른 enum 값 찾기
fun getMnemonic(color: Color) = // 함수의 반환 값으로 when 식을 직접 사용
when (color) { // 색이 특정 enum 상수와 같을 때 그 상수에 대응하는 문자열을 return
Color.RED -> "빨강"
Color.ORANGE -> "주황"
Color.Yellow -> "노랑"
Color.GREEN -> "초록"
Color.BLUE -> "파랑"
Color.INDIGO -> "남색"
Color.VIOLET -> "보라"
}
println(getMnemonic(Color.BLUe)) // 파랑
// 한 when 분기 안에 여러 값 사용하기
fun getWarmth(color: Color) = when(color) {
Color.RED, Color.ORANGE, Color.YELLOW -> "warm"
Color.GREEN -> "neutral"
Color.BLUE, Color.INDIGO, Color.VIOLET -> "cold"
}
println(getWarmth(Color.ORANGE)) // warm
- 위의 두 예제에서 Color라는 enum 클래스 이름을 enum 상수 이름 앞에 붙인 전체 이름 사용하였음
- 상수 값을 임포트하면 위의 코드를 더 간단하게 만들 수 있음
// enum 상수 값을 임포트해서 enum 클래스 수식자 없이 enum 사용하기
import ch02.colors.Color
import ch02.colors.Color.*
fun getWarmth(color: Color) = when(color) {
RED, ORANGE, YELLO -> "warm"
GREEN -> "neutral"
BLUE, INDIGO, VIOLET -> "cold"
}
📌 when과 임의의 객체를 함께 사용
- 코틀린에서 when은 자바의 switch보다 훨씬 더 강력함
- 분기 조건에 상수만을 사용할 수 있는 자바의 switch와는 달리 코틀린 when의 경우 임의의 객체를 허용함
// when의 분기 조건에 여러 다른 객체 사용하기
fun mix(c1: Color, c2: Color) =
when (setOf(c1, c2)) {
setOf(RED, YELLOW) -> ORANGE // when 식의 인자로 아무 객체나 사용할 수 있음
setOf(YELLOW, BLUE) -> GREEN // when은 이렇게 인자로 받은 객체가 각 분기 조건에 있는 객체와 같은지 테스트
setOF(BLUE, VIOLET) -> INDIGO // 두 색을 혼합해서 다른 색을 만들 수 있는 경우를 열거
else -> throw Exception("Dirty color") // 매치되는 분기 조건이 없으면 예외 실행
}
println(mix(BLUE, YELLOW)) // GREEN
- 코틀린 표준 라이브러리에는 인자로 전달받은 여러 객체를 그 객체들을 포함하는 집합인 Set 객체로 만드는 setOf라는 함수가 있음
- 집합은 원소가 모여 있는 컬렉션으로 각 원소의 순서는 중요하지 않음 ex) setOf(c1, c2) == setOf(c2, c1)
- when 식은 인자 값과 매치하는 조건 값을 찾을 때까지 각 분기를 검사(동등성)
- 모든 분기 식에서 만족하는 조건을 찾을 수 없는 경우 else 분기의 문장을 계산
📌 인자 없는 when 사용
- 인자가 없는 when 식을 사용하면 불필요한 객체 생성을 막을 수 있음
- 코드는 읽기 어려워질 수 있지만 성능을 더 향상시키기 위해 사용되는 경우가 자주 있음
- when에 아무 인자도 없으려면 각 분기의 조건이 불리언 결과를 계산하는 식이어야 함
// 인자가 없는 when (위의 식 변환)
fun mixOptimized(c1: Color, c2: Color) =
when { // 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(mixOptimized(BLUE, YELLOW)) // GREEN
📌 스마트 캐스트
- 자료형이 다른 값의 계산(예를 들어, 실수와 정수의 계산일 때)에서 매번 자료형을 변경 하는 것은 번거로움
- 하지만 코틀린에서는 'is'를 사용하여 이를 쉽게 도와줄 수 있음
- 자바의 instanceof와 비슷하지만 instanceof는 변수의 타입만 확인 가능한 반면에 is는 타입 검사 후 자동으로 형변환을 해줌
- 컴파일러가 캐스팅을 수행해주며 이를 스마트 캐스트라고 함
interface Expr // expr interface
class Num(val value: Int) : Expr // 입력받은 값 반환
class Sum(val left: Expr, val right: Expr) : Expr // 왼쪽, 오른쪽과 같이 2개의 값을 받아 더한 뒤 그 값 반환
// 값을 반환하는 역할을 하는 eval 메소드
fun eval(e: Expr) : Int {
if (e is Num) {
val n = e as Num // 불필요한 타입 변환(이미 if 조건식에서 스마트 캐스팅이 진행되었기 때문에)
return n.value
}
if(e is Sum) {
return eval(e.left) + eval(e.right) // 변수 e에 대한 스마트캐스트
}
throw IllegalArgumentException("Unknown expression")
}
// 값을 만들어내는 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
// if 중첩 대신 when 사용하기
fun eval(e: Expr) : Int =
when(e) {
is Num ->
e.value
is Sum ->
eval(e.right) + eval(e.left)
else ->
throw IllegalArgumentExceptoin("Unknown expression")
}
📌 if와 when의 분기에서 블록 사용
- if나 when 모두 분기에 블록을 사용할 수 있음
- 그런 경우 블록의 마지막 문장이 블록 전체의 결과가 됨
- 예제로 봤던 eval 함수에 로그를 추가하고 싶다면 각 분기를 블록으로 만들고 블록의 맨 마지막에 그 분기의 결과 값을 위치시키면 됨
// 분기에 복잡한 동작이 들어가 있는 when 사용하기
fun evalWithLogging(e: Expr) : Int =
when(e) {
is Num -> {
println("num: ${e.value}")
e.value
}
is Sum -> {
val left = evalWithLoggint(e.left)
val right = evalWithLogging(e.right)
println("sum: $left + $right")
left + right
}
else -> throw IllegalArgumentException("Unknown expression")
}
728x90
반응형
'Studying > Kotlin' 카테고리의 다른 글
[Kotlin In Action] 3장. 함수 정의와 호출(1) - 컬렉션과 함수 만들기 (0) | 2023.05.02 |
---|---|
[Kotlin In Action] 2장. 코틀린 기초(4) - 코틀린의 예외 처리 (0) | 2023.04.24 |
[Kotlin In Action] 2장. 코틀린 기초(3) - while과 for 루프 (0) | 2023.04.24 |
[Kotlin In Action] 2장. 코틀린 기초(1) - 함수와 변수 / 클래스와 프로퍼티 (0) | 2023.04.20 |
[Kotlin In Action] 1장. 코틀린이란 무엇이며, 왜 필요한가? (0) | 2023.04.17 |