[Kotlin in Action] 26. 수신 객체 지정 람다 (with, apply)

반응형
728x90
반응형

수신 객체 지정 람다

수신 객체를 명시하지 않고 람다의 본문 안에서 다른 객체의 메서드를 호출할 수 있게 한다.

 


with 라이브러리 함수

with를 사용하여 어떤 객체의 이름을 반복하지 않고도 그 객체에 대해 다양한 연산을 수행할 수 있다.

 

with 사용 전
/** 매번 result 반복 사용 */
fun alphabet1() : String {
    val result = StringBuilder()

    for (letter in 'A'..'Z') {
        result.append(letter)
    }

    result.append("\nNow I know the alphabet!")
    return result.toString()
}

fun main() {
    println(alphabet1())
}

 

with 사용 후
fun alphabet2() : String {
    val stringBuilder = StringBuilder()

    /* 파라미터는 2개다. 첫번째는 StringBuilder, 두번째 람다 */
    return with(stringBuilder) { /* 메서드를 호출하려는 수신 객체를 지정한다. */
        for (letter in 'A'..'Z') {
            this.append(letter)  /* this를 명시해서 앞에서 지정한 수신 객체의 메서드를 호출한다. */
        }

        append("\nNow I know the alphabet!")  /* "this"를 생략하고 메서드를 호출한다. */
        this.toString() /* 람다에서 값을 반환한다. */
    }
}

with 함수는 첫번째 인자로 받은 객체를 두번째 인자로 받은 람다의 수신 객체로 만든다. 인자로 받은 람다 본문에서는 this를 사용해 그 수신 객체에 접근할 수 있다.

 

단순화

StringBuilder의 인스턴스를 만들고 즉시 with에게 인자로 넘기고, 람다 안에서 this를 사용하여 그 인스턴스를 참조한다. with가 반환하는 값은 람다 코드를 실행한 결과다. 그 결과는 람다 식의 본문에 있는 마지막 식의 값이다.

fun alphabet3() = with(StringBuilder()) {
    for (letter in 'A'..'Z') {
        append(letter)
    }

    append("\nNow I know the alphabet!")
    toString() // 람다 값 반환
}

 

 

apply 확장 함수

apply는 항상 자신에게 전달된 객체(수신 객체)를 반환한다. apply는 확장 함수로 정의되어있다.

 

apply 사용

apply의 수신 객체가 전달받은 람다의 수신 객체가 된다.

이 함수에서 apply를 실행한 결과는 StringBuilder 객체다. 그 객체의 toString을 호출해서 String 객체를 얻는다.

fun alphabet() = StringBuilder().apply {
    for (letter in 'A'..'Z'){
        append(letter)
    }

    append("\nNow I know the alphabet!")
}.toString()

fun main(args: Array<String>) {
    println(alphabet())
}

이런 apply 함수는 객체의 인스턴스를 만들면서 즉시 프로퍼티 중 일부를 초기화해야하는 경우 유용하다.
자바에서는 보통 별도의 Builder 객체가 이런 역할을 담당한다.

 

apply를 TextView 초기화에 사용하기
fun createViewWithCustomAttributes(context: Context) =
    TextView(context).apply {
        text = "Sample Text"
        textSize = 20.0
        setPadding(10, 0, 0, 0)
    }

TextView 인스턴스를 만들고 즉시 그 인스턴스를 apply에 넘긴다. 

  • apply에 전달된 람다 안에서의 수신객체 : TextView

원하는대로 TextView의 메서드를 호출하거나 프로퍼티를 설정할 수 있다. 람다를 실행하고 나면 apply는 람다에 의해 초기화된 TextView 인스턴스를 반환한다. 그 인스턴스가 createViewWithCustomAttributes()의 결과가 된다.

 

 

표준 라이브러리 buildString 함수 사용

표준 라이브러리 buildString 함수를 사용하면 더 단순화할 수 있다.
buildString은 StringBuilder 객체를 만드는 일과 toString 호출해주는 일을 알아서 해준다.

  • 수신 객체 지정 람다 : buildString의 인자
  • 수신 객체 : 항상 StringBuilder
fun alphabet5() = buildString {
    for (letter in 'A'..'Z') {
        append(letter)
    }

    append("\nNow I know the alphabet!")
}

 

 

 

반응형

Designed by JB FACTORY