[Kotlin] Scope functions의 정의와 사용 방법

[Kotlin] Scope functions의 정의와 사용 방법

Scope functions이란?

Scope functions는 객체의 범위(scope) 내에서 코드 블록을 실행할 수 있게 하는 함수이다.

let, run, with, apply, also 등이 있으며, 이 함수들은 객체의 속성에 접근하거나 객체를 다르게 처리하는데 유용하다.

이 스코프는 객체의이름을 사용하지 않고 it,this등을 통해 객체에 접근이 가능하다.

FunctionObject referenceReturn valueIs extension function
letitLambda resultYes
runthisLambda resultYes
run-Lambda resultNo: called without the context object
withthisLambda resultNo: takes the context object as an argument
applythisObject referenceYes
alsoitObject referenceYes

위 표를 살펴보면 2가지로 분류되는것을 알 수 있는데

  • Object reference 가 it 인가 this인가
  • 반환값이 Object reference 인가 Lambda result 인가

이 값들중 특이하게 with가 남게되는데 여러 동작들을 어떤상황에서 사용하는지 알아보자

1) with

with 은 이미 생성된 객체에 대해 일관적인 작업을처리할때 유용하다.

with를 사용할때
private fun initView() = with(binding) {
        //viewpager adapter
        viewPager.adapter = viewPagerAdapter
        //viewpager slide
        viewPager.isUserInputEnabled=false
       }
with를 사용하지 않을때
private fun initView() {
        //viewpager adapter
        binding.viewPager.adapter = viewPagerAdapter
        //viewpager slide
        binding.viewPager.isUserInputEnabled=false
       }
  • 본인은 binding을 사용할때 with를 사용했었는데 xml의 Id값을불러올때 반복되는 코드를 줄이기위해 with로 정해줬다.

  • 이값은 this로 참조할 수 있고 내가 사용한 방법처럼 this를 생략할 수도 있다.

val person = Person()
val result = with(person) {
    name = "John"
    age = 30
    "$name is $age years old."
}

println(result) // 출력: John is 30 years old.

  • 위와같이 with를 사용했을때 반환 값이 Lambda result 이기때문에 마지막라인에 다른 데이터를 추가하면 이값이 반환된다.

2) apply

apply는 객체의 초기화 블록으로 사용되며, 객체 자체를 반환한다.

data class Car(var brand: String, var model: String, var year: Int)

val myCar = Car("Toyota", "Camry", 2022).apply {
    year = 2023
    model = "Corolla"
}

println(myCar) // 출력: Car(brand=Toyota, model=Corolla, year=2023)

  • with 은 인자로 context object 를 받지만, apply 는 extension function 이기 때문에 객체를 생성해서 할당하기 전에 사용이 가능하다.

  • apply 코드 블록이 모두 수행된 후 인스턴스가 할당되기 때문에 apply객체 생성시점에서 초기화를 할 때 유용하다.

3) also

also 는 객체를 람다에 전달하고 그 객체를 반환한다.

주로 부수 효과를 일으키는 작업에 사용된다.

val numbers = mutableListOf(1, 2, 3)

numbers.also {
    it.add(4)
    println("List after adding 4: $it") // 출력: List after adding 4: [1, 2, 3, 4]
}.removeAt(1)

println("List after removing element at index 1: $numbers") // 출력: List after removing element at index 1: [1, 3, 4]

  • apply 와 유사해 보이는데 차이점은 apply 는 Lambda function 에 인자를 넘겨주지 않기 때문에 this를 이용해 참조한다.
  • 그에 반해 also는 Lambda function 에 인자를 넘겨주기 때문에 인자를 it 이나 다른 이름을 부여해 참조가 가능하다.

4) run

run은 수신 객체에 람다를 실행해 결과를 반환하고 this를 사용한다.

val message = run {
    val greeting = "Hello"
    val name = "Kotlin"
    "$greeting, $name!"
}

println(message) // 출력: Hello, Kotlin!
  • with와 유사하지만 객체를 생성해서 할당하기전에 사용이 가능하다는점이 다르다.
val nameDoubleLength = Person.withDefaultName()
    .run { name.length * 2 }
  • 객체를 변수로 할당할 필요 없이 필요한값만 바로 반환받을 수 있다.
val nameDoubleLength = person?.run { name.length * 2 }
    ?: 0
  • Null 회피용도로도 사용할 수 있다.

5) let

let 은 주어진 블록을 호출하고, 결과를 반환할때 주로 사용한다.

val length: Int? = "Hello, Kotlin".let {
    println(it) // 출력: Hello, Kotlin
    it.length
}

println("문자열 길이: $length") // 출력: 문자열 길이: 13

정리

  • with

    • 객체 할당 이후 객체에게 다양한 작업들을 함께(with) 할 때
  • apply
    • 객체에게 무언가를 적용(apply) 할 때
  • also
    • 객체에게 명령을 내리기 직전에 추가적인(also) 작업을 함께 수행시키고 싶을 때
  • run
    • 객체를 생성하거나 사용하는 시점에서 다양한 작업을 수행시킨 후 결과를 반환받고 싶을 때
  • let
    • 객체를 생성하거나 사용하는 시점에서 다양한 작업을 수행시킨 후 결과를 반환받고 싶을 때, 명시적인 네이밍이 필요할 때

© 2023. All rights reserved.

AgileCatch