5. [5] 수신 객체 지정 람다

  • with과 apply는 편리하며 다수의 사람이 사용중이다.
  • 코틀린 람다의 독특한 기능인 지정 람다는 수신 객체를 명시하지 않고 람다의 본문 안에서 다른 객체의 메서드를 호출한다.

(1) with

fun alphabet(): String {
 val result = StringBuilder()
 for(letter in 'A'..'Z') result.append(letter)
 result.append("\\n Now I Know The Alphabet!")
 return result.toString()
}
fun alphabet(): String {
 val stringBuilder = StringBuilder()
 return with(stringBuilder) { // 메서드를 호출하려는 수신 객체 지정
   for(letter in 'A'..'Z') this.append(letter) // this를 명시하여 앞에서 지정한 객체 호출
   append("\\n Now I Know The Alphabet!") // this를 생략하여 메서드 호출
   this.toString() // 람다에서 값 반환
}
}
fun alphabet() = with(StringBuilder()) {
 for(letter in 'A'..'Z') append(letter)
 append("\\n Now I Know The Alphabet!")
 toString()
}
println(alphabet())
// ABCDEFGHIJKLMNOPQRSTUVWXYZ
// Now I Know The Alphabet!
  • 위 예제 에서는 result에 대해서 다른 여러 메서드를 호출하면서 매번 result를 반복 사용했다.
  • 아래 예제에서 with문은 두 개의 파라미터를 가진 함수이다. [stringBuilder, lambda]
  • with 함수는 첫 번째 인자로 받은 객체를 두 번째 인자로 받은 람다의 수신 객체로 만든다.
  • 이는 일반적인 this처럼 this와 dot을 생략하여 프로퍼티나 메서드에 사용해도 수신 객체의 멤버에 접근할 수 있다.
  • 불필요한 stringBuilder 변수를 없애면 식의 결과를 함수가 바로 반환하게 한다.

(2) apply

fun alphabet() = StringBuilder().apply {
 for(letter in 'A'..'Z') append(letter)
 append("\\n Now I Know The Alphabet!")
}.toString()
fun alphabet() = buildString {
 for(letter in 'A'..'Z') append(letter)
 append("\\n Now I Know The Alphabet!")
}
fun createViewWithCustomAttributes(context: Context) {
 TextView(context).apply {
   text = "Sample Text"
   textSize = 20.0
   setPadding(10, 0, 0, 0)
}
}

[apply 함수의 특징]

  1. 항상 자신에게 수신객체를 반환한다.
  2. 수신 객체가 전달받은 람다의 수신 객체가 된다.
  3. 객체의 인스턴스를 만들면서 즉시 프로프티 중 일부를 초기화 하는데 유용하다.
  4. 함수의 본문에 간결한 식을 사용할 수 있다.
  5. 람다가 실행되고 나서 람다에 의해 초기화된 인스턴스가 함수의 결과가 된다.
  • with과 apply는 수신 객체 지정 람다를 활용하는 일반적인 예제 중 하나로, 구체적인 패턴에도 활용 가능하다.
  • 표준 라이브러리와 buildString을 사용하면 StringBuilder의 생성과 toString의 호출을 알아서 대신한다.
  • 수신 객체 지정 람다는 DSL을 만들 때, 매우 유용하다.