어떤 객체의 이름을 반복하지 않고도 객체에 대해 여러 연산을 수행할 수 있다면 좋을 것이다. 이를 지원하는 도구로 코틀린은 with과 apply를 지원한다.
fun alphabet(): String {
val result = StringBuilder()
for(letter in 'A'..'Z') {
result.append(letter)
}
result.append("\nNow I know the alphabet!")
return result
}
fun alphabet(): String =
with(StringBuilder()) {
for(letter in 'A'..'Z') {
this.append(letter) // this로 수신 객체 명시 가능
}
append("\nNow I know the alphabet!") // this 생략 가능
toString()
}
with는 로직을 적용할 수신객체를 지정해 넘겨주고 로직을 수행한다.
수신객체를 반환할 필요가 있다면 with의 반환값으로 this를 지정해도 되지만 코틀린은 수신객체를 반환하는 apply를 지원한다.
fun alphabet(): String =
StringBuilder().apply {
for(letter in 'A'..'Z') {
this.append(letter) // this로 수신 객체 명시 가능
}
append("\nNow I know the alphabet!") // this 생략 가능
}.toString()
apply는 적용하다 라는 뜻 그대로 수신 객체에 로직을 적용하고 수신 객체를 반환한다.
유의점
코틀린에서 람다식을 밖으로 빼거나 괄호를 생략할 수 있다는 점에서 착각하기 쉬운데
apply와 with은 코틀린에서 제공하는 언어적 기능이 아니라 표준 라이브러리 함수이다.
apply와 with 뒤에 오는 중괄호는 사실 람다식이며 it이 this인 특수한 람다식이다.실제 형태 : apply(logic = { ... }), with(Object, logic = { ... })
let 함수도 수신 객체 지정 람다의 일종이지만 특수한 쓰임을 가지고 있다.
fun sendEmailTo(email: String){
println(email)
}
fun getEmail() = when((1..2).random()){
2 -> "test@test.com"
else -> null
}
fun main(){
getEmail()?.let {
sendToEmail(it)
} ?: println("email is null!")
}
어떤 함수를 수행할 때 넘겨지는 인자가 널인지 아닌지 검사할 필요가 있을 수 있다. let 함수는 이것을 간단하게 해준다.
// if 분기
val result = getEmail()
if(result != null) {
sendEmailTo(result)
}
else {
println("email is null")
}
// let 사용
getEmail()?.let {
sendEmailTo(it)
} ?: println("email is null!")
let 함수는 널 검사를 수행하고 넘겨지는 수신 객체가 널인 경우 아무일도 일어나지 않는다. 널이 아닌 경우 람다로 넘겨진 로직을 수행한다.
if 분기를 통해 따로 널 검사를 수행하는 것보다 코드가 간결해지기 때문에 익숙해지면 좋을 것 같다.