본문 바로가기
안드로이드/Kotlin

[Kotlin] 범위 지정 함수(Scope function)

by jinwo_o 2024. 12. 9.

Scope function

  • 객체의 이름을 사용하지 않고, 객체에 접근이 가능하게 하는 함수
  • 특정 객체에 대한 작업을 블록 안에 넣어 실행할 수 있도록 하는 함수 (feat. kotlinworld)
Function Object reference Return value Is extension function
let it Lambda result Yes
run this Lambda result Yes
run - Lambda result No: called without the context object
with this Lambda result No: takes the context object as an argument
apply this Object reference Yes
also it Object reference Yes

 

it

  • 람다식 내부에서 사용되는 암시적 변수
  • 람다식에서 인자가 하나인 경우 it 을 사용해서 인자를 참조할 수 있다.

 

this

  • 클래스의 인스턴스를 참조하는데 사용된다.
  • this 를 사용하여 클래스 내부에서 멤버 변수나 멤버 함수를 참조할 수 있다.

let

inline fun <T, R> T.let(block: (T) -> R): R
  • 확장 함수이므로, 객체를 생성해서 할당하기 전에 사용이 가능하다.
  • 인자로 Lambda function 을 받기 때문에 곧바로 Lambda function 에 해당하는 코드 블록을 작성할 수 있다.
  • Lambda function 에 인자를 명시적으로 전달하기 때문에 인자를 it 이나 다른 이름을 부여해 참조가 가능하다.
  • 반환 값이 Lambda Result 이다. 임의로 생성한 값이나 객체를 반환할 수 있다.

 

  • 객체를 생성하거나 사용하는 시점에서 다양한 작업을 수행시킨 후 결과를 반환받고 싶을 때, 명시적인 네이밍이 필요할 때 유용하다.
val firstPerson = Person(
    email = "firstPerson@gmail.com",
    age = 28,
)
val secondPerson = Person(
    email = "secondPerson@email.com",
    age = 58,
)
val people = listOf(firstPerson, secondPerson)

val firstPersonEmailDoubleLength = people.first()
    .let { firstPerson -> 
        val secondPerson = Person(
            email = "wow@wow.com",
            age = 10,
        )
        firstPerson.email.length * 2
    }
  • mutable 변수의 null check 를 진행하고 싶을 때 유용하다.
private var str: String? = null

fun process() {
    if (str != null) {
        println(str?.length)
    }
}
private var str: String? = null

fun process() {
    str?.let { println(it.length) }
}
  • nullable 체이닝을 끊어내고 싶을 때 유용하다.
fun process(string: String?): List? {
    return string?.asIterable()?.distinct()?.sorted()
}

@Nullable
public final List process(@Nullable String string) {
   List var2;
   if (string != null) {
      Iterable var10000 = StringsKt.asIterable(
                           (CharSequence)string);
      if (var10000 != null) {
         var2 = CollectionsKt.distinct(var10000);
         if (var2 != null) {
            var2 = CollectionsKt.sorted((Iterable)var2);
            return var2;
         }
      }
   }

   var2 = null;
   return var2;
}
fun process(string: String?): List? {
    return string?.let {
        it.asIterable().distinct().sorted()
    }
}

@Nullable
public final List process(@Nullable String string) {
   List var10000;
   if (string != null) {
      int var4 = false;
      var10000 = CollectionsKt.sorted(
                   (Iterable)CollectionsKt.distinct(
                      StringsKt.asIterable((CharSequence)string)));
   } else {
      var10000 = null;
   }

   return var10000;
}

 

run

inline fun <R> run(block: () -> R): R
inline fun <T, R> T.run(block: T.() -> R): R
  • 단일 lambda function 을 인자로 받는 버전과 확장 함수로 이루어진 버전이 있다.
  • 인자로 Lambda function 을 받기 때문에 곧바로 Lambda function 에 해당하는 코드 블록을 작성할 수 있다.
  • with 와 유사하지만, run 은 확장 함수 버전 때문에 객체를 생성해서 할당하기 전에 사용이 가능하다는 차이가 생긴다.
  • 두 경우 모두 반환 값이 Lambda Result 이다. 임의로 생성한 값이나 객체를 반환할 수 있다.

 

  • 객체를 생성하거나 사용하는 시점에서 다양한 작업을 수행시킨 후 결과를 반환받고 싶을 때 유용하다.
val nameDoubleLength = Person.withDefaultName()
    .run { name.length * 2 }

 

with

inline fun <T, R> with(receiver: T, block: T.() -> R): R
  • 확장 함수가 아니다. 객체를 인자로 전달받아 사용한다.
  • 두 번째 인자로 람다 함수를 받기 때문에 곧바로 Lambda function 에 해당하는 코드 블록을 작성할 수 있다.
  • Lambda function 은 확장 함수 형태로 코드 블록 내에 수신 객체가 암시적으로 전달된다. this 를 이용해 참조한다.
  • 반환 값이 Lambda Result 이다. 임의로 생성한 값이나 객체를 반환할 수 있다.

 

  • 이미 생성된 객체에 일괄적인 작업을 처리할 때 유용하다.
val result = with(person) {
    isCool = true
    isAwesome = true
    koreanName = “현구막"
    "nice"
}

 

apply

inline fun <T> T.apply(block: T.() -> Unit): T
  • 확장 함수이므로, 객체를 생성해서 할당하기 전에 사용이 가능하다.
  • 인자로 Lambda function 을 받기 때문에 곧바로 Lambda function 에 해당하는 코드 블록을 작성할 수 있다.
  • Lambda function 은 확장 함수 형태로 코드 블록 내에 수신 객체가 암시적으로 전달된다. this 를 이용해 참조한다.
  • 반환 값이 Object reference 이다. 코드 블록 내에 전달된 수신객체를 그대로 다시 반환한다.

 

  • 코드 블록이 모두 수행된 후 인스턴스가 할당되기 때문에 객체 생성시점에서 초기화를 할 때 유용하다.
val person = Person(
    email = "aaa@gmail.com",
    age = 28,
).apply { name = "홍길동" }

 

also

inline fun <T> T.also(block: (T) -> Unit): T
  • 확장 함수이므로, 객체를 생성해서 할당하기 전에 사용이 가능하다.
  • 인자로 Lambda function 을 받기 때문에 곧바로 Lambda function 에 해당하는 코드 블록을 작성할 수 있다.
  • Lambda function 에 인자를 명시적으로 전달하기 때문에 인자를 it 이나 다른 이름을 부여해 참조가 가능하다.
  • 반환 값이 Object reference 이다. 코드 블록 내에 전달된 수신객체를 그대로 다시 반환한다.

 

  • 이름 그대로 객체에게 명령을 내리기 직전에 추가적인(also) 작업을 함께 수행시키고 싶을 때 유용하다.
val people = listOf(
    Person(
        email = "firstPerson@gmail.com",
        age = 28,
    ),
    Person(
        email = "secondPerson@email.com",
        age = 58,
    )
)

people.first()
    .also { firstPerson ->
        println("이메일 길이: ${firstPerson.email.length}")
        println("현재 나이: ${firstPerson.age}")
    }.increaseAge()

 

Kotlin Scope function 올바르게 사용하기

let, also 와 같은 Scope function 을 오래전부터 사용해왔지만 정확히 어떤 상황에 어떤 Scope function 을 사용하면 좋을지 감이 잘 안잡혔다. 그러다 최근 Scope function 관련 질문도 받았었겠다, 각각의 Scop

hyeon9mak.github.io

 

코틀린 it과 this 정확히 무슨 개념일까?

항상 간편하게 사용했지만 정확히 알지 못했던 it과 this의 개념을 정리해봤습니다. it it은 람다식 내부에서 사용되는 암시적 변수입니다. 람다식에서 인자가 하나인 경우 it을 사용해서 인자를

like-while.tistory.com