[Kotlin in Action] 5.5 수신 객체 지정 람다: with와 apply
코틀린에는 수신 객체를 명시하지 않고 람다의 본문 안에서 다른 객체의 메소드를 호출할 수 있다. 그런 람다를 수신 객체 지정 람다(lambda with receiver)라고 부른다.
5.5.1 with 함수
어떤 객체의 이름을 반복하지 않고도 그 객체에 대한 다양한 연산을 수행할 수 있다면 좋을 것이다. 코틀린에서는 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()
}
>>> println(alphabet())
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Now I know the alphabet!
위 코드를 어떤 객체의 이름을 반복하지 않고 연산을 수행하는 with를 사용하여 리팩토링해보자.
// with와 식을 본문으로 하는 함수를 활용해 알파벳 만들기
fun alphabet() = with(StringBuilder()) {
for (letter in 'A'..'Z') {
append(letter)
}
append("\nNow I know the alphabet!")
toString()
}
불필요한 StringBuilder 변수를 없애면 alphabet 함수가 식의 결과를 바로 반환하게 된다. 따라서 식을 본문으로 하는 함수로 표현할 수 있다. StringBuilder의 인스턴스를 만들고 즉시 with에게 인자로 넘기고, 람다 안에서 this를 사용해 그 인스턴스를 참조한다.
with가 반환하는 값은 람다 코드를 실행한 결과며, 그 결과는 람다 식의 본문에 있는 마지막 식의 값이다. 하지만 때로는 람다의 결과 대신 수신 객체가 필요한 경우도 있다. 그럴 때는 apply 라이브러리 함수를 사용할 수 있다.
5.5.2 apply 함수
apply 함수는 거의 with와 같다. 유일한 차이란 apply는 항상 자신에게 전달된 객체(=수신 객체)를 반환한다는 점 뿐이다. apply를 써서 alphabet 함수를 다시 리팩토링해보자.
// apply를 사용해 알파벳 만들기
fun alphabet() = StringBuilder().apply {
for (letter in 'A'..'Z') {
append(letter)
}
append("\nNow I know the alphabet!")
}.toString()
apply는 확장 함수로 정의돼 있다. apply의 수신 객체가 전달받은 람다의 수신 객체가 된다. 이 함수에서 apply를 실행한 결과는 StringBuilder객체다. 따라서 그 객체의 toString을 호출해서 toString 객체를 얻을 수 있다.