코틀린의 표준 라이브러리는 다양한 기능 과 편리한 기능으로 함수형 프로그래밍을 쉽게 적용할 수 있도록 도와줍니다.
그중에서도 apply, with, let, also, run 과 같은 범위 지정함수에 대해 알아보겠습니다.
이 5개의 함수는 전달받는 인자와 작동 방식, 결과가 매우 비슷하기 때문에 많은 경우에 서로를 대체 해서 사용할수도 있습니다.
이 함수들은 두가지 구성 요소를 가집니다.
- 수신 객체 (확장함수가 호출되는 대상이 되는 객체)
- 수신 객체 지정 람다 (lambda with receiver)
apply 사용 규칙
수신 객체 람다 내부에서 수신 객체의 함수를 사용하지 않고 수신 객체 자신을 다시 반환 하려는 경우에 apply 를 사용합니다.
수신 객체 의 프로퍼티 만을 사용하는 대표적인 경우가 객체의 초기화 이며, 이곳에 apply 를 사용합니다.
inline fun <T> T.apply(block: T.() -> Unit): T
//Calls the specified function block with this value as its receiver and returns this value.
val peter = Person().apply {
// apply 의 블록 에서는 오직 프로퍼티 만 사용합니다!
name = "Peter"
age = 18
}
//apply를 사용하지 않은 코드
val peter = Person()
peter.name = "Peter"
peter.age = 18
also 사용 규칙
수신 객체 람다가 전달된 수신 객체를 전혀 사용 하지 않거나 수신 객체의 속성을 변경하지 않고 사용하는 경우 also 를 사용합니다.
also 는 apply 와 마찬가지로 수신 객체를 반환 하므로 블록 함수가 다른 값을 반환 해야하는 경우에는 also 를 사용할수 없습니다.
예를 들자면, 객체의 사이드 이팩트를 확인하거나 수신 객체의 프로퍼티에 데이터를 할당하기 전에 해당 데이터의 유효성을 검사 할 때 매우 유용합니다.
inline fun <T> T.also(block: (T) -> Unit): T
//Calls the specified function block with this value as its argument and returns this value.
class Book(author: Person) {
val author = author.also {
requireNotNull(it.age)
print(it.name)
}
}
//also를 사용하지 않는 코드
class Book(val author: Person) {
init {
requireNotNull(author.age)
print(author.name)
}
}
with 사용 규칙
Non-nullable (Null 이 될수 없는) 수신 객체 이고 결과가 필요하지 않은 경우에만 with 를 사용합니다.
수신객체에 대한 작업 후 마지막 라인을 리턴합니다. run과 완전히 똑같지만, run은 확장 함수로 사용되지만, with는 수신 객체를 파라미터로 받아 사용한다는 점이 다릅니다.
inline fun <T, R> with(receiver: T, block: T.() -> R): R
//Calls the specified function block with the given receiver as its receiver and returns its result.
class Person {
var name: String? = null
var age: Int? = null
}
val person: Person = getPerson()
with(person) {
print(name)
print(age)
}
//with를 사용하지 않는 코드
val person: Person = getPerson()
print(person.name)
print(person.age)
let 사용 규칙
다음과 같은 경우에 let 을 사용합니다.
- 지정된 값이 null 이 아닌 경우에 코드를 실행해야 하는 경우.
- Nullable 객체를 다른 Nullable 객체로 변환하는 경우.
- 단일 지역 변수의 범위를 제한 하는 경우.
inline fun <T, R> T.let(block: (T) -> R): R
//Calls the specified function block with this value as its argument and returns its result.
getPromotablePerson()?.let {
// null 이 아닐때만 실행됩니다.
promote(it)
}
//let을 사용하지 않는 경우
val person: Person? = getPromotablePerson()
if (person != null) {
promote(person)
}
연산 결과를 임시 변수에 할당하지 않고 처리하는 경우
val num = mutableListOf(1, 5, 14, 2, 7, 16, 24, 8)
val result = num.filter{it > 10}
println(result) //[14, 16, 24]
//result 변수 없이 바로 사용 가능
num.filter{it > 10}.let{println(it)} //[14, 16, 24]
코드 블럭에 it을 인자로 가지는 단일 함수가 있다면 람다 대신 메서드 참조(::)를 사용할 수도 있습니다.
.let{println(it)} --> .let(::println)
run 사용 규칙
어떤 값을 계산할 필요가 있거나 여러개의 지역 변수의 범위를 제한하려면 run 을 사용합니다.
매개 변수로 전달된 명시적 수신객체 를 암시적 수신 객체로 변환 할때 run ()을 사용할수 있습니다.
수신객체를 리턴하지 않고, run 블럭의 마지막 라인을 리턴합니다.
수신객체에 대해 특정한 동작을 수행한 후 결과값을 리턴받고자 할 때 주로 사용됩니다.
inline fun <T, R> T.run(block: T.() -> R): R
//Calls the specified function block with this value as its argument and returns its result.
data class Person (var name: String = "", var age: Int = 0) {
fun isOld(): Boolean = age > 50
}
val person = Person("james", 55)
val isOldAge = person.run {
age = 40
isOld() //return 값
}
'Kotlin' 카테고리의 다른 글
reduce, fold (0) | 2022.03.26 |
---|---|
lateinit, lazy (0) | 2022.03.26 |
backing field <custom getter(), setter() 설정> (0) | 2022.03.26 |
val, const val (0) | 2022.03.25 |
람다, 고차함수, 함수합성, 클로저 (0) | 2022.03.25 |