Kotlin Scoping functions

반응형

Scoping Functions

코틀린은 쉽게, 자주 사용되는 HOF(High Order Function)을 내장하고 있습니다. 각 함수가 어떤 특성을 가지고 있고 어떤 상황에서 쓰일 수 있는지 알아보겠습니다. 주의할 점은 각각의 경우 함수가 어떤 scope 내에서 동작하는지 구별하는 것입니다.

  1. apply
  2. let
  3. also
  4. run
  5. with

먼저 HOF의 특성을 먼저 이해 해야 합니다. HOF은 함수 블럭을 입력으로 받아서 함수 또는 값을 반환하는 함수입니다. 4가지 함수도 함수 블럭을 받아 처리하는 함수입니다. 이 때 차이점은 다음의 두가지 입니다.

  • receiver 객체를 parameter로 받는지(=객체 scope 내인지)?
    • T.() 의 경우 해당 객체의 scope내의 함수이기 때문에 this 키워드를 사용할 수 있습니다.
    • (T) 의 경우 객체를 parameter로 받은 형태이기 때문에 it 키워드를 사용할 수 있습니다.
  • 반환값이 receiver 객체인지(=함수의 리턴값인지)??
    • → Unit 의 경우 함수 블럭에서는 리턴값이 없고, receiver 객체를 반환합니다.
    • → R 의 경우 함수 블럭에서 반환한 값을 반환합니다.
Kotlin Scoping Functions

apply

inline fun <T> T.apply(block: T.() -> Unit): T {
    block()
    return this
}

val peter = Person().apply {
    // Use only perperties
    name = "Peter"
    age = 10
}

let

inline fun <T, R> T.let(block: (T) -> R): R {
    return block(this)
}

/**
 * Null check & run
 */
getPerson()?.let {
    book.person = it
}

also

inline fun <T> T.also(block: (T) -> Unit): T {
    block(this)
    return this
}

/**
 * validation
 */
class Book(author: Person) {
    val author = author.also {
      requireNotNull(it.age)
      print(it.name)
    }
}

run

inline fun <T, R> T.run(block: T.() -> R): R {
    return block()
}

위의 4가지 함수와 비슷하지만 다른 함수는 with 입니다. 명시적으로 receiver를 받아서 처리하는 HOF이기 때문입니다. 이는 자바의 try-with와 비슷하기 때문에 오히려 이해하기 쉬울 겁니다.

with

inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    return receiver.block()
}

val first = DemoClass("s", 2)
val result = with(first) {
    val second = DemoClass(this.a+"b", this.b+1)
    second
}
result.a shouldBe "sb"

receiver: T

Receiver 객체를 argument로 받는다.

block: T.() → R

Code block은 T.()로 해당 객체 내의 함수처럼 동작하게 해준다. 즉, 코드 블럭이 객체의 scope내로 정의되는 것이다. 이는 this 키워드를 쓸 수 있고 this가 가리키는 객체가 Receiver 객체라는 것이다.

: R

반환값은 코드 블럭에서 반환(Return)하는 값이다.

반응형