본문 바로가기

Kotlin

코틀린의 스코프 함수(scope functions)

 

코틀린 기초 문법을 공부할 때, 스코프 함수라는 것을 접하고 처음에는 잘 이해가 가지 않았다.

이걸 어느 상황에서 써야 하는지, 왜 써야 하는지 잘 와닿지 않았기 때문이다.

점점 코틀린으로 코딩을 하면서 스코프 함수를 사용해야 하는 상황이 어떤 것인지 알게 되었고, 이제는 꽤 자주 사용하게 되었다.

 

적절하게 사용하면 편리한 스코프 함수에 대해 정리해 보려고 한다.

 

스코프 함수

 

이름에서 보듯이, 스코프 함수는 코틀린에서 특정 객체의 스코프(범위) 내에서 작업을 수행하도록 도와주는 함수이다.

이 함수들은 블록 내에서 객체에 대한 일련의 작업을 실행하게 한다. 또한 스코프 함수를 사용하면 코드를 훨씬 간결하고 가독성 있게 작성할 수 있다.

대표적인 스코프 함수는 let, apply, also, run, with가 있다. 각 스코프 함수는 코드 블록 내에서 객체를 it이나 this로 참조할 수 있으며, 반환값으로는 블록의 결과나 객체 자체를 반환할 수 있다.

 

let

* 객체를 it으로 참조하고 반환값이 코드 블록의 결과

* 주로 null 검사를 위해 ?.let{ } 형태로 사용 (개인적으로 가장 자주 쓰는 스코프 함수!!)

 

예시

1. 스코프 함수 없이 작성

 

val name: String? = getName()
if (name != null) {
    println("Hello, ${name.length} characters!") // name이 null이 아니면 길이를 출력
}

 

2. 스코프 함수 let 사용하여 작성

val name: String? = getName()
name?.let { 
    println("Hello, ${it.length} characters!") 
}

* null 체크하는 if 문을 제거할 수 있다.

* null 체크와 로직을 묶어 한 번에 작성할 수 있어 코드가 짧아지고 가독성이 좋다.

 

 

apply

* 객체를 this로 참조하고 반환 값은 해당 객체

* 객체의 속성을 초기화하거나, 수정할 때 주로 사용한다. 

 

예시

1. 스코프 함수 없이 작성

val person = Person()
person.name = "Alice"
person.age = 25
person.job = "Engineer"

 

2. 스코프 함수 apply 사용하여 작성

val person = Person().apply {
    name = "Alice"
    age = 25
    job = "Engineer"
}

* 객체 이름 반복을 줄일 수 있다.

 

also

* 객체를 it으로 참조, 반환값은 해당 객체

* 객체에 대한 추가 작업을 수행하거나 디버깅 로그를 찍는데 유용함

 

예시

1. 스코프 함수 없이 작성

val numbers = mutableListOf("one", "two", "three")
println("Initial list: $numbers")
numbers.add("four")

 

2. 스코프 함수 also 사용하여 작성

val numbers = mutableListOf("one", "two", "three").also {
    println("Initial list: $it")
}.apply { add("four") }

also를 통해 리스트 초기 상태를 출력하고, apply를 사용하여 add 작업을 이어서 처리하여 더 간결하게 구현할 수 있다.

 

 

run

* 객체를 this로 참조, 반환값이 코드 블록의 결과

* 객체를 초기화하면서 결과값을 계산해야 할 때 유용 

 

예시

1. 스코프 함수 없이 작성

val name = "Kotlin"
val length = if (name != null) {
    println("The length of name is ${name.length}")
    name.length
} else 0

 

2. 스코프 함수 run 사용하여 작성

val length = "Kotlin".run {
    println("The length of name is $length")
    length
}

작업 후 반환값을 바로 받을 수 있어서 중간 변수를 줄이고 코드를 간소화할 수 있다.

 

with

* 객체를 인자로 받아 this로 참조, 반환값은 코드블록의 결과

* 주로 이미 생성된 객체에 대해 여러 작업을 수행할 때 사용

 

예시

1. 스코프 함수 없이 작성

val person = Person("Alice", 25, "Engineer")
println(person.name)
println(person.age)
println(person.job)

 

2. 스코프 함수 with 사용하여 작성

with(person) {
    println(name)
    println(age)
    println(job)
}

* 객체의 속성에 반복적으로 접근하는 코드를 줄일 수 있다.

 

 


요약

 

  • let, run : 코드 블록의 결과 반환
  • apply, also : 객체 자체 반환
  • let, also : it 사용
  • apply, run, with : this 사용

그런데 위 내용을 달달 외워서 쓰기보다는 사용하면서 익히게 되는 것 같다. 

더불어 영어가 모국어이거나, 모국어에 가깝게 영어를 사용할 수 있다면 스코프 함수의 이름에서 직관적으로 스코프 함수에 대하여 더 잘 체득할 수 있을 것 같다.