[Kotlin] 범위 함수(Scope Function)를 사용하여 클래스 속성 및 메소드 접근 2 (with, run, also)

문승연·2023년 7월 31일
0

Kotlin 기본

목록 보기
8/11

아래 정의를 볼때 재네릭 약어의 의미를 기억하고 보면 이해가 빠를 것이다.

[E]: Element
[K]: Key
[N]: Number
[T]: Type
[V]: Value
[R]: Return Type

with

with의 기본 정의는 아래와 같다.

inline fun <T, R> with(receiver: T, block: T.() -> R): R

withlet과 달리 확장 함수가 없다. 첫 번째 인수에 임의의 타입 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

run의 기본 정의는 다음과 같다.

inline fun <T, R> T.run(block: T.() -> R): R

run은 모든 타입 T의 확장 함수로 그 T를 받는 메소드를 인수로 받는다.

fun main() {
    val str = "moonliam".run { uppercase() }
    println(str)
}
MOONLIAM

runletwith의 합체 버전으로 객체에 포함된 함수를 실행하고, 그 결과를 반환할 때 사용한다. 예를 들면, 아래와 같다.
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

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))
  }
}

레퍼런스)
https://www.devkuma.com/docs/kotlin/scope-functions/

profile
"비몽(Bemong)"이라는 앱을 개발 및 운영 중인 안드로이드 개발자입니다.

0개의 댓글