프로그래밍 노트/Kotlin

[Kotlin] 수신 객체 지정 람다: with와 apply

깡냉쓰 2020. 12. 14. 00:11
728x90
반응형

코틀린 람다의 독특한 기능은 바로 수신 객체를 명시하지 않고 람다의 본문 안에서 다른 객체의 메소드를 호출할 수 있게 하는 것이다. 그런 람다를 수신 객체 지정 람다(lamda with receiver) 라고 부른다.

with 함수

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

fun alphabet(): String{
    val result = StringBuilder()
    for(letter in 'A'..'Z'){
        result.append(letter)
    }
    result.append("\nNow I know the alphabet!")
    return result.toString()
}

이 예제에서 result에 대해 다른 여러 메소드를 호출하면서 배번 result를 반복 사용했다. 만약에 result를 더 자주 반복해야 했다면 어땠을까? with로 다시 작성해보자

fun alphabet2(): String{
    val stringBuilder = StringBuilder()
    // 메소드를 호출하려는 수신 객체를 지정
    return with(stringBuilder){
        for (letter in 'A'..'Z'){
            // this를 명시해서 수신 객체의 메소드 호출
            this.append(letter);
        }
        // this 생략 가능
        append("\nNow I know the alphabet!")
        this.toString()
    }
}

with는 실제로 파라미터가 2개있는 함수다.

  • 첫번째 파라미터: stringBuilder
  • 두번째 파라미터: 람다
    람다를 괄호 밖으로 빼내는 관례를 사용해서 특별 구문처럼 보이지만, 사실은 아래와 같은 문구랑 같다.
    with(stringBuilder, {...})
    리펙토링을 더 해보면 아래와 같이 표현할 수 있다.
    fun alphabet3() = with(StringBuilder()){
      for (letter in 'A'..'Z'){
          // this를 명시해서 수신 객체의 메소드 호출
          this.append(letter)
      }
      // this 생략 가능
      append("\nNow I know the alphabet!")
      this.toString()
    }

apply 함수

apply함수는 거의 with와 같다. 유일한 차이는 apply는 항상 자신에게 전달된 객체(즉 수신 객체)를 반환한다는 점이다.

fun alphabet4() = StringBuilder().apply{
    for (letter in 'A'..'Z'){
        append(letter)
    }
    append("\nNow I know the alphabet!")
}.toString()

apply는 확장 함수로 정의돼 있다. apply의 수신 객체가 전달받은 람다의 수신 객체가 된다. 이 함수에서 apply를 실행한 결과는 StringBuilder 객체다.

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

apply 객체 초기화에 활용하는 예로 안드로이드 TextView 컴포넌트를 만들어서 특성 중 일부를 설정해보자.

fun createViewWithCustomAttributes(context: Context) = 
    TextView(context).apply {
        text = "Simple Text"
        textSize = 20.0
    }

람다를 실행하고 나면 apply는 람다에 의해 초기화된 TextView 인스턴스를 반환한다. 그 인스턴스는 createViewWithCustomAttributes 함수의 결과가 된다.

728x90
반응형