아래 정의를 볼때 재네릭 약어의 의미를 기억하고 보면 이해가 빠를 것이다.
[E]: Element
[K]: Key
[N]: Number
[T]: Type
[V]: Value
[R]: Return Type
with의 기본 정의는 아래와 같다.
inline fun <T, R> with(receiver: T, block: T.() -> R): R
with는 let과 달리 확장 함수가 없다. 첫 번째 인수에 임의의 타입 T를 받는다. 두 번째 인수로 함수를 가지고는 있지만, T을 받으면서 사용하는 메소드를 필요로 한다.
fun main() {
val str = with("moonliam") { this.uppercase() }
println(str)
}
MOONLIAM
위의 예시에서 this는 "moonliam"을 뜻한다. 이는 생략 가능하다.
Example 1
fun main() {
val numbers = mutableListOf("one", "two", "three")
with(numbers) {
println("'with' is called with argument $this")
println("It contains $size elements")
}
}
Output
'with' is called with argument [one, two, three]
It contains 3 elements
Example 2
import java.awt.Dimension
import javax.swing.JFrame
fun main() {
val frame: JFrame = with(JFrame("My App")) {
size = Dimension(600, 400)
defaultCloseOperation = JFrame.EXIT_ON_CLOSE
isVisible(true)
this
}
}
Output
run의 기본 정의는 다음과 같다.
inline fun <T, R> T.run(block: T.() -> R): R
run은 모든 타입 T의 확장 함수로 그 T를 받는 메소드를 인수로 받는다.
fun main() {
val str = "moonliam".run { uppercase() }
println(str)
}
MOONLIAM
run은 let과 with의 합체 버전으로 객체에 포함된 함수를 실행하고, 그 결과를 반환할 때 사용한다. 예를 들면, 아래와 같다.
Example 1
fun main() {
val numbers = mutableListOf("one", "two", "three")
val countEndsWithE = numbers.run {
add("four")
add("five")
count { it.endsWith("e") }
}
println("numbers: $numbers")
println("There are $countEndsWithE elements that end with e.")
}
Output
numbers: [one, two, three, four, five]
There are 3 elements that end with e.
마지막으로 실행된 함수의 결과값을 반환하므로 run 내부 함수의 실행 순서가 바뀔 경우 run의 결과값도 바뀌게 된다.
Example 2
val numbers = mutableListOf("one", "two", "three")
val countEndsWithE = numbers.run {
count { it.endsWith("e") }
add("four")
add("five")
}
println("numbers: $numbers")
println("There are $countEndsWithE elements that end with e.")
Output
numbers: [one, two, three, four, five]
There are true elements that end with e.
also의 기본 정의는 다음과 같다.
inline fun <T> T.also(block: (T) -> Unit): T
also의 장점은 2가지가 있다.
1. 이름을 붙일 수 있다.
2. 람다 식의 안팎에서 this의 의미가 변하지 않는다.
fun main() {
val str = "moonliam".also { it.uppercase() }
println(str)
}
also 함수는 apply 함수와 유사한 부분이 많으니 비교해보도록 하자.
Before) apply를 활용한 예시
val button = Button(this).apply {
text = "Click me"
setOnClickListener {
startActivity(Intent(this@MainActivity, NextActivity::class.java))
}
}
After) also를 활용한 예시
val button = Button(this).also { button ->
button.text = "Click me"
button.setOnClickListener {
startActivity(Intent(this, NextActivity::class.java))
}
}