본문 바로가기

코틀린

코틀린: in과 범위 연산

범위 관련 연산에 관한 보충 설명입니다. 자세한 내용은 쉽게 다가가는 최신 프로그래밍: 코틀린 - 2.6 범위 관련 연산을 참고하기 바랍니다.

코틀린에서 연산자 in은 코드를 읽기 쉽게 만들어주는 재롱덩어리(?)입니다. 어떤 영어 문자가 소문자인지 확인하려면 'a'에서 'z' 사이에 속하는지 조사해야겠죠. 여러분이 아래처럼 코딩했다면 아직 프로그램 초보자입니다.

fun main() {
    val ch = 'k'
    println(isSmallCase(ch))
}

fun isSmallCase(c: Char) : Boolean {
    return ('a' <= c && c <= 'z')
}

아래처럼 코딩했다면 함수를 좀 쓸 줄 아는구나 정도입니다.

fun isSmallCase(c: Char) : Boolean {
    return (c.isLowerCase())
}

 

우리가 확인하고 싶은 소문자 범위가 'k'부터 'p'까지이면 어떻게 할까요? 아쉽지만 isLowerCase()는 사용할 수 없습니다. 이럴 때 in 연산자와 범위 타입을 함께 사용하면 됩니다. 

fun isSmallCase(c: Char) : Boolean {
    return (c in 'k'..'p')
}

혹시 연산자 in 이 함수 contains() 에 대한 연산자 중복(operator overloading)관계인 것을 잊은 건 아니겠죠. contains() 함수를 사용할 수는 있지만, 연산자 in을 사용하는 게 더 깔끔하고 코드를 읽기 쉽습니다.

fun isSmallCase(c: Char) : Boolean {
    return (('k'..'p').contains(c))
}

 

범위 타입이란 용어를 위에서 사용했습니다. 범위 타입이란 .. 연산자를 사용하는 것을 말합니다. 시작..끝에서 시작과 끝을 모두 포함하는 폐구간입니다. 범위 타입 변수를 선언하는 게 귀찮아서(?) 대부분 직접 범위를 지정합니다. 아래처럼 사용하면 확실하죠.  in 연산자와 범위 타입은 뗄레야 뗄 수 없는 사이라는 걸 이해했나요? 조건식 뿐만 아니라 for 문과 같은 반복문에서도 자주 사용하기 때문에 잘 이해해야 합니다.

fun isSmallCase(c: Char) : Boolean {
    val chRange: CharRange = 'k'..'p'
    return c in chRange
}

 

간단한 응용 예제를 만들어볼까요. Double 타입은 정밀도(precision)가 소수점이하 15자리로 가장 높습니다. 아래 예에서 변수 d2의 값은 3.14가 아닙니다. 정말? 확인해 보세요. 그래서, d1과 d2의 값은 아주 아주 작은 차가 있습니다. 함수 inAllowableRange()에서 오차 허용 범위를 0.001까지 지정하면, 이제 두 수는 같은 수로 판별할 수 있습니다. 오차 허용 범위는 필요에 따라 언제든 수정할 수 있죠. 직접 코드를 입력하고 실행해보면 알 수 있습니다. Don't miss it!

import kotlin.math.abs

fun main() {
    val d1 = 3.14
    val d2 = 0.0314 * 1E2
    println("d1= $d1, d2 = $d2, diff = ${abs(d1-d2)}")
    println(d1-d2)
    if (inAllowableRange(d1-d2)) {
        println("two values are the same")
    } else {
        println("two values are the different")
    }
}

fun inAllowableRange(d: Double) : Boolean {
    val numberRange = 0.0..0.001
    return d in numberRange
}

 

마무리 예제(Wrap-up exercise)를 다뤄볼까요. 아래 코드는 정상 동작할까요?

fun main() {
    println(isCorrectPrefix("cx"))
    println(isCorrectPrefix("ck"))
}

fun isCorrectPrefix(s: String) : Boolean {
    return s in "ca".."cp"
}