[Android] Scope Function(let, with, run, apply, also)?

WonDDak·2023년 11월 14일
0

Android

목록 보기
3/6

코틀린으로 앱개발을 하다보면 let,with,run,apply,also라는 놈들은 한번씩은 본적이 있을것이다.

애들은 뭐하는 애들일까?

Scope Function는 공식 홈페이지에서 다음과 같이 소개하고있다.

The Kotlin standard library contains several functions whose sole purpose is to execute a block of code within the context of an object. When you call such a function on an object with a lambda expression provided, it forms a temporary scope. In this scope, you can access the object without its name. Such functions are called scope functions. There are five of them: let, run, with, apply, and also.

즉 이를 이용하면 람다식을 이용한 scope가 생기게된다.

차이

비슷한 기능을 가졌지만 참조하거나 값을 반환하는것이 조금씩은 다르다.

Context object: this or it

Scope에 전달된 람다 내에서 Context object는 실제 이름 대신 짧은 참조로 사용할 수 있습니다.
각 범위 함수는 컨텍스트 개체를 참조하는 두 가지 방법이 있는데 , this 또는 it 중 하나를 사용합니다.
둘 다 동일한 기능을 제공하므로 다양한 사용 사례에 대한 각각의 장단점을 설명하고 사용에 대한 권장 사항을 제공합니다.

  • apply, also : this
  • let, run, with : it

Return value

Scope에따라 반환하는 결과에 따라 다릅니다.

  • apply, also : Context object를 반환합니다.
  • let, run, with : 람다 결과값을 반환합니다.

예시

apply와 also는 Context Object 자체를 반환한다 하였습니다. 다음과 같은 예시를 볼 수있습니다.

val numberList = mutableListOf<Double>()
numberList.also { println("Populating the list") }
    .apply {
    	// this는  numberList 자체를 반환하므로 apply scope 내에서 list에add가 가능하다.
        add(2.71)
        add(3.14)
        add(1.0)
    }
    .also { println("Sorting the list") }
    .sort()

Populating the list
Sorting the list
[1.0, 2.71, 3.14]

또는 이런식으로 반환값 자체에 also/apply를 이용해 추가 작업도 가능합니다.

fun getRandomInt(): Int {
   return Random.nextInt(100).also {
       writeToLog("getRandomInt() generated value $it")
   }
}

val i = getRandomInt()

INFO: getRandomInt() generated value 83

run을 이용한 계식 예시입니다.

val numbers = mutableListOf("one", "two", "three")
val countEndsWithE = numbers.run { 
   add("four")
   add("five")
   count { it.endsWith("e") }
}
println("There are $countEndsWithE elements that end with e.")

There are 3 elements that end with e.


Scope

이제 좀더 자세하게 알아봅시다.

let

객체 결과값에 하나 이상의 함수를 호출하는 경우 사용합니다.(보통 ?를 이용한 null처리에도 많이 쓰입니다)

val numbers = mutableListOf("one", "two", "three", "four", "five")
val resultList = numbers.map { it.length }.filter { it > 3 }
println(resultList)    
val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }.filter { it > 3 }.let { 
    println(it)
    // and more function calls if needed
} 

두개의 식은 같은 결과값을 가지지만 아래것이 좀더 편해보이죠?

null처리에도 다음과 같이 많이씁니다

val nullString : String? = "Hello is Not Null"
nullString?.let{ println(it) }

with

with는 확장 함수가 아닙니다. 그래서 인자를 넣어줘야하지만 scope내에서 this로 접근이 가능합니다.

val numbers = mutableListOf("one", "two", "three")
with(numbers) {
    println("'with' is called with argument $this")
    println("It contains $size elements")
}
val firstAndLast = with(numbers) {
    "The first element is ${first()}," +
    " the last element is ${last()}"
}
println(firstAndLast)

'with' is called with argument [one, two, three]
It contains 3 elements
The first element is one, the last element is three

run

사실 애는 with랑 거의똑같습니다. 확장함수 여부의 차이정도로 생각하면 되겠습니다.

apply

apply는 결과값으로 Context Object 자체를 반환합니다.
(주로 초기화 할때 많이 사용합니다)

val adam = Person("Adam").apply {
	// scope내 에서 this는 Person 자체를 뜻함
    age = 32
    city = "London"        
}
println(adam)

Person(name=Adam, age=32, city=London)

also

also는 apply와 비슷하나 주로 액션을 할때 사용한다 합니다.

val numbers = mutableListOf("one", "two", "three")
numbers
    .also { println("The list elements before adding new one: $it") }
    .add("four")

추가로 it의 경우 이름 지정이 가능합니다.

val numbers = mutableListOf("one", "two", "three")
numbers
    .also { list ->
    	println("The list elements before adding new one: $list") 
     }
    .add("four")

정리

FunctionContext ObjectReturn Value
letitLambda result
with(run)thisLambda result
applythisContext Object
alsoitContext Object
profile
안녕하세요. 원딱입니다.

0개의 댓글