Kotlin Scope 함수

Jong_Han·2021년 12월 27일
0

Kotlin

목록 보기
1/2

Scope 함수란?

Object context 내에서 코드 블럭을 실행하는 코틀린의 5가지 함수를 말합니다.

블록 내에서는 객체의 이름을 명시하지 않아도 해당 객체에 접근할 수 있어서 코드를 보다 간결하게 작성할 수 있도록 해주지만, 중첩되면 오히려 가독성을 해치게 되는 경우가 발생하니 너무 남발하지 않는 것이 좋습니다.

종류로는 with, run, also, apply, let가 있으며, 처음 접할 때에는 모두 비슷한 기능을 한다고 느낄 수 있어서 각각의 차이점 알고 사용해야 합니다.

Scope 함수의 차이점은 크게 두 가지 입니다.

  1. 객체의 접근을 암시적(this)으로 하는지, 파라미터(it)로 하는지
  2. 실행의 결과가 객체 자신인지, 코드 블럭의 결과인지

위 두 가지 차이점을 중점으로 5가지의 Scope 함수를 알아보도록 하겠습니다.

run

public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

run은 확장함수이기 때문에, 객체를 this로 접근할 수 있으며, 람다식의 결과 값을 리턴 합니다.

따라서, 접근하는 객체의 메소드나 프로퍼티를 이용한 결과 값이 필요한 경우에 사용합니다.

그 외에도 객체의 메소드에 여러 번 접근할 때도 사용합니다.

사용 예시

val book1 = Book("동화",1000)
val salePrice = book1.run { price * 0.8 } // 800

with

public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

with는 확장함수가 아니지만, 파라미터로 받은 객체를 블록의 파라미터로 받기 때문에, this로 접근할 수 있으며, 람다식의 결과 값을 리턴합니다.

수신 객체가 Non-nullable일 때만 사용 가능하며, 결과 값이 필요 없을 때 주로 사용합니다.

run과는 확장함수의 여부 외에는 큰 차이점이 없습니다.

사용예시

val book1 = Book("동화",1000)
        with(book1) {       
            println( "제목 : $title, 가격 : $price" )
        }

apply

public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

apply는 확장함수이기 때문에, 객체를 this로 접근할 수 있으며, 객체 자신을 리턴합니다.

주로 객체의 프로퍼티를 변경 또는 지정해주면서 초기화 할 때 사용합니다.

사용예시

val morning = Car().apply { 
            name = "morning"
            price = 100
        }

let

public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

let은 확장함수지만, 람다식에서 파라미터로 수신 객체를 받기 때문에, it을 통해 객체에 접근이 가능합니다.

리턴값은 람다식의 결과값 입니다.

주로 객체의 null check를 할 때 사용합니다.

사용예시

fun test(str: String?) {
        str?.let {
            println("result :: $it")
        } ?: println("result is null")
    }

test에서 주어진 파라미터 str이 null이라면 result is null을 출력하고, null이 아니라면 result :: $it을 출력하게 됩니다.

also

public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

also는 확장함수지만, 람다식에서 파라미터로 수신 객체를 받기 때문에 객체에 it을 통해 접근하며, 객체 자신을 리턴합니다.

객체의 초기화에 주로 사용되는 apply와 다르게, 객체 내 프로퍼티를 변경하지 않고 사용할 때 also를 사용합니다.

사용예시

val soul = Car()
soul.also { println("car name: ${it.name}") }

정리

코틀린에서 제공하는 Scope 함수는 객체 접근 방식과 리턴값으로 구분할 수 있으며 다음과 같습니다.

수신 객체 자신람다식 결과
thisapplyrun, with
italsolet
profile
안드로이드 개.....발자?

0개의 댓글