[Kotlin] #범위 지정 함수 - let, apply, run, with, also
💡 범위 지정 함수란? (= Scope Function)
범위 지정 함수는 특정 범위 블록 내에서는 특정 객체를 this, it을 통해 접근하거나 조작할 수 있는 함수를 말한다.
즉, 범위 지정 함수를 사용하면 임시 Scope가 형성된다.
이렇게 사용하면 뭐가 좋냐?
일단 가독성이 증가하여 유지보수가 쉽고, 불필요한 변수 선언을 방지할 수 있다.
Kotlin에서는 범위 지정 함수 5가지(let, apply, with, also, run)를 제공하고 있다.
이 함수들은 수신 객체를 어떻게 전달하는지, 반환 값이 무엇인 지에 따라 차이점이 있다.
💡 Type 1 : let 함수
fun<T, R> T.let(block : (T) -> R) : R
let은 수신 객체를 람다의 Parameter로 전달하기 때문에 'it'을 이용해 수식 객체에 접근할 수 있다.
그리고 Block의 마지막 줄을 반환한다.
아래의 예제 코드를 보면 Block의 마지막인 "!!"를 출력하는 것을 볼 수 있다.
var str: String = "Hello"
str = str.let {
it.plus(" World")
"!!"
}
println(str)
하지만 보통 let의 경우 '?' 연산자와 함께 Null Check를 할 때 자주 사용한다.
var str1: String? = null
var str2: String? = "Hello"
str1?.let { println(str1) }
str2?.let { println(str2) }
'?' 연산자의 역할에 대해 모른다면 아래의 포스터를 참고하자.
💡 Type 2 : apply 함수
fun <T> T.apply(block : T.() -> Unit): T
apply는 수신 객체를 람다의 수신 객체로 전달하기 때문에 this를 이용해 수식 객체에 접근하거나
특정한 명시를 하지 않아도 수식 객체에 접근할 수 있다.
그리고 수신 객체 그 자체를 반환한다.
그래서 어떤 객체의 프로퍼티를 수정하고 싶을 때 유용하게 사용할 수 있다.
아래 예제 코드를 보면 Person객체에 대한 프로퍼티를 수정해서 출력하는 것을 볼 수 있다.
또한, this로 수신 객체에 접근할 수도 있고, 아무런 명시가 없어도 수신 객체에 접근할 수 있는 것을 알 수 있다.
fun main() {
val P = Person().apply {
this.name = "Chris" // this로 접근
age = 20 // 아무런 명시 없이 접근
}
println(P.toString())
}
data class Person(var name: String = "", var age: Int = 0) {
}
💡 Type 3 : run 함수
// 1. 수신객체 없이 익명함수로 사용
fun<R> run(block : () -> R) : R
// 2. 수신객체를 호출하여 사용
fun<T, R> T.run(block : T.() -> R) : R
run은 수신 객체를 지정하지 않고 익명 함수로 사용하거나 수신 객체를 호출하여 사용할 수 있다.
하지만 반환 값은 Block의 마지막 줄로 동일하다.
우선 익명 함수로 사용할 경우엔 내부에 수신 객체를 명시해줘야 한다.
fun main() {
val P = Person("Chris", 20)
val result = run {
P.age = 25 // 구체적 명시
false // 반환값
}
println(P)
println(result)
}
data class Person(var name: String = "", var age: Int = 0) {
}
수신 객체를 이용할 땐 수신 객체 그 자체로 전달하기 때문에 명시하지 않거나 'this'를 이용해 수신 객체에 접근할 수 있다.
fun main() {
val P = Person().run {
this.name = "Chris" // this로 접근
age = 20 // 명시 없이 접근
true // 반환값
}
println(P.toString())
}
data class Person(var name: String = "", var age: Int = 0) {
}
💡 Type 4 : with 함수
fun<T, R> with(receiver : T, block T.() -> R) : R
with은 run과 똑같이 동작한다.
하나의 차이점이라면 run은 확장 함수로써 사용이 되지만, with은 수식 객체를 Parameter로 받아 사용한다.
위에 run의 예제 코드와 똑같이 사용하면 다음과 같이 작성할 수 있다.
fun main() {
val P = Person("", 0)
val result = with(P){
this.name = "Chris" //this로 접근
age = 20 // 명시 없이 접근
true // 반환값
}
println(P.toString())
println(result)
}
data class Person(var name: String = "", var age: Int = 0) {
}
run과 똑같이 사용되기 때문에 코드의 간결성을 위해서는 run을 사용하는 것이 좋다.
💡 Type 5 : also 함수
fun<T> T.also(block: (T) -> Unit): T
also는 수신 객체를 람다의 Parameter로 전달하기 때문에 'it'을 이용해 수식 객체에 접근할 수 있다.
그리고 수신 객체 그 자체를 반환한다.
apply와 유사하게 프로퍼티를 수정할 때 사용할 수 있는데, 보통 수정뿐 아니라 추가적인 작업이 필요할 때 사용한다.
fun main() {
var num = 1
val P = Person().also {
it.name = "Chris" //it으로 접근
it.age = 20
num += 1
} // 수신 객체 그 자체를 반환
println(P.toString())
println(num)
}
data class Person(var name: String = "", var age: Int = 0) {
}
'Language > Kotlin' 카테고리의 다른 글
[Kotlin] #코틀린에서의 Null 처리 - Null Safety (0) | 2022.04.13 |
---|---|
[Kotlin] #반복문 사용법 (0) | 2022.04.05 |
[Kotlin] #var와 val의 차이점 (0) | 2022.03.29 |