호출된 객체를 this로 받아, 람다 블록 안에서 객체의 속성이나 메서드에 접근해 작업을 수행하고 객체 자체를 반환한다
`this` 값을 수신자로 하여 지정된 함수 [block]을 호출하고 `this` 값을 반환합니다.
inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this // 호출된 객체 자체 반환
}
fun Int.apply(block: Int.() -> Unit): Int {
block()
return this
}
val result = 5.apply {
println("number: $this")
}
println(result)
// Int는 불변 객체(immutable)이므로, apply 내부에서 값을 변경할 수 없다
val result = mutableListOf(1, 2, 3).apply {
add(4)
remove(1) // 리스트를 수정하지만, 반환값은 Unit임
println("Updated list: $this")
}
println(result) // [2, 3, 4]
// mutableListOf(1, 2, 3)를 수정하고 호출된 객체 자체를 반환함
Unit : apply는 람다 블록이 아무 값도 반환하지 않아도 괜찮도록 설계되었다
람다 블록의 반환값은 무시되며, apply는 객체 자체(this)를 반환한다.
val person = Person().apply {
name = "Alice"
age = 30
}
println(person) // Person(name=Alice, age=30)
객체 생성 후 속성을 한 줄로 설정 가능.
apply 블록을 통해 객체 속성을 초기화하고, 최종적으로 해당 객체를 반환함
호출된 객체를 it으로 전달하여 람다 블록에서 부수 작업을 수행한 후, 객체 자체를 반환한다
주된 목적은 부수 작업을 수행하는 것이다
`this` 값을 인수로 사용하여 지정된 함수 [block]을 호출하고 `this` 값을 반환합니다.
inline fun <T> T.also(block: (T) -> Unit): T {
block(this)
return this // 호출된 객체 자체 반환
}
fun Int.also(block: (Int) -> Unit): Int {
block(this) // 호출된 객체(현재 Int)를 it으로 람다 블록에 전달함
return this
}
val number = 10.also {
println("number : $it")
}
val myList = mutableListOf(1, 2, 3).also {
it.add(4)
println("Updated list: $it")
}
println(myList) // [1, 2, 3, 4]
val userName = "John".also {
println("User name: $it")
}
println(userName)
// apply를 사용하면 this로 접근해야 하고, 속성을 설정하거나 초기화하려는 느낌을 줄 수 있어
// 부수 작업의 의도를 명확히 전달하지 못함
val myList = mutableListOf(1, 2, 3)
.also { println("Before: $it") }
.apply { add(4) }
println(myList) // [1, 2, 3, 4]
// apply만 사용하면 로깅과 수정을 혼합하게 되어 의도가 불분명
val number = 42.also {
require(it > 0) { "Number must be positive" }
}
println(number)
// apply를 사용하면 속성을 설정하려는 의도가 아닌데도 불구하고 this로 접근해야 함
어떤 객체를 잠시 빌려서 원하는 작업을 하고, 결과를 돌려주는 함수
`this` 값을 인수로 사용하여 지정된 함수 [block]을 호출하고 결과를 반환합니다.
inline fun <T, R> T.let(block: (T) -> R): R {
return block(this)
}
fun let(block: (Int) -> Int): Int {
return block(this) // this는 let을 호출한 객체
}
val number = 5
val result = number.let { it * 2 }
println(result)
// block 함수 : { it * 2 }
// this : number
// block(this) : 5 * 2
위 예제에서는 let이 빌린 객체는 number다.
호출된 객체를 this로 사용하여 작업을 수행하고, 그 결과를 반환하는 함수
지정된 함수 [block]을 호출하고 결과를 반환합니다.
inline fun <T, R> T.run(block: T.() -> R): R {
return block()
}
fun Int.run(block: Int.() -> String): String {
return block()
}
val result = 10.run {
"The number is $this" // this는 10
}
println(result)
val person = Person("Alice", 25)
val info = person.run {
println("Person name: $name")
println("Person age: $age")
"$name is $age years old"
}
println(info) // Alice is 25 years old
객체를 초기화하거나 작업을 수행할 때 사용하는데 둘이 차이점은 반환값이다.
그렇다면 각각의 사용목적은 뭘까?
객체 자체가 아니라 결과 메시지를 사용하려는 의도
val message = Character("Alice", 25).run {
"$name, age $age, is ready for the game!"
}
println(message) // Alice, age 25, is ready for the game!
초기화된 객체 자체가 중요. 캐릭터를 설정한 뒤, 그 객체를 다음 작업에서 사용할 것
val character = Character().apply {
name = "Alice"
age = 25
}
println(character) // Character(name=Alice, age=25)
객체를 전달받아 여러 작업을 묶어서 실행하고, (최종) 결과를 반환하는 함수
매개변수로 객체를 전달받는다
지정된 [receiver]를 수신자로 하여 지정된 함수 [block]을 호출하고 결과를 반환합니다.
inline fun <T, R> with(receiver: T, block: T.() -> R): R {
return receiver.block()
}
fun with(receiver: Int, block: Int.() -> String): String {
return receiver.block()
}
val result = with(10) {
"The number is $this"
}
println(result) // The number is 10
// 10이 receiver로 전달
// this는 10
여러 UI 속성을 설정하는 작업을 하나로 묶어 처리할 때 사용
val button = Button(context)
with (button) {
text = "Click Me"
textSize = 16f
setOnClickListener { println("Button clicked!") }
}
작업 그룹화를 지원하는 것은 동일한데 각각의 사용목적은 뭘까?
객체 작업 그룹화에 초점이 맞춰져 있다면, with가 더 나은 선택이다
apply랑 also는 객체 자체를 반환하고 also는 임시
run이랑 let은 결과를 반환하고 let은 임시
with은 작업을 묶어서 수행하고 결과를 반환
null 타입 검토는 run이랑 let만
apply와 also : 객체 자체를 반환
apply : 객체를 설정하거나 초기화한 후 반환. (this 사용)
also : 부수 작업(로깅, 디버깅 등)을 수행한 후 반환. (it 사용, 임시 작업에 적합)
run과 let : 작업 결과를 반환
run : 객체와 관련된 작업을 그룹화하고, 결과를 반환. (this 사용)
let : 임시로 객체를 사용하고, 결과를 반환. (it 사용, 임시 작업에 적합)
with : 작업을 묶어서 수행하고 결과를 반환
객체를 매개변수로 전달받아 작업을 묶어서 처리하고 결과를 반환. (this 사용)
run과 let만 null 타입 검토 지원
apply, also, with는 호출된 객체가 null일 경우 사용 불가