스코프 함수 — 개념, 종류 및 Kotlin에서의 활용

저자: IT Sectr 게시일: 2026-06-23 읽는 시간: 8 분

Kotlin의 스코프 함수는 객체의 컨텍스트에서 코드 블록을 실행하는 다섯 가지 표준 라이브러리 함수(let, run, with, apply, also)입니다. 이들은 객체에 접근하는 방식(it 또는 this를 통해)과 반환 값(컨텍스트 객체 또는 람다 결과)이 다릅니다. Kotlin 문서(2026)에 따르면, 올바른 스코프 함수 선택은 보일러플레이트 코드를 25~40% 줄여줍니다. 스코프 함수는 객체 초기화, 구성 및 변환을 선언적 스타일로 작성하는 데 도움을 줍니다.

핵심 요점

  • 스코프 함수 — 객체 컨텍스트에서 작업하기 위한 다섯 가지 Kotlin 함수(let, run, with, apply, also)
  • this를 통한 컨텍스트 — run, with, apply는 this를 사용하여 객체의 메서드를 직접 호출 가능
  • it를 통한 컨텍스트 — let과 also는 명시적 명명과 함께 객체를 it 매개변수로 전달
  • 객체 반환 — apply와 also는 호출 체인을 위해 컨텍스트 객체를 반환
  • 결과 반환 — let, run, with는 람다의 마지막 표현식을 반환

스코프 함수란?

스코프 함수는 Kotlin 표준 라이브러리에 내장된 다섯 가지 함수(let, run, with, apply, also)의 집합입니다. 각 함수는 람다를 받아 람다 내부의 코드가 특정 객체의 컨텍스트에서 실행되도록 일시적으로 스코프를 변경합니다. 이는 여러 호출에서 객체 이름을 반복하지 않도록 하고 관련 작업을 하나의 블록으로 그룹화합니다.

두 가지 주요 특성이 스코프 함수를 구분합니다: 컨텍스트 객체에 접근하는 방식(this 또는 it을 통해)과 반환 값(컨텍스트 객체 자체 또는 람다 결과)입니다. this를 통한 접근은 객체를 암시적 수신자로 만듭니다 — 메서드와 속성이 접두사 없이 호출됩니다. it를 통한 접근은 객체를 람다의 명시적 매개변수로 전달합니다. 객체를 반환하면 체인이 가능하고, 결과를 반환하면 변환된 값을 할당할 수 있습니다.

역사적으로 스코프 함수는 클래식 Builder 패턴과 초기화를 위한 임시 변수의 대체로 등장했습니다. 별도의 빌더 클래스를 만드는 대신, 개발자는 apply { 속성1 = ...; 속성2 = ... }를 작성합니다. 이는 코드 양을 줄이고 초기화를 더 읽기 쉽게 만듭니다. Kotlin 생태계에서 스코프 함수는 모든 프레임워크와 라이브러리에서 표준 언어 관용구로 사용됩니다.

스코프 함수 비교: this vs it, 객체 반환 vs 결과

올바른 스코프 함수의 선택은 두 가지 질문에 의해 결정됩니다: 객체에 접근하기 위해 this를 사용할지 it을 사용할지, 그리고 객체 자체를 반환할지 람다 결과를 반환할지입니다. 두 가지 이진 특성의 조합은 네 가지 가능한 옵션을 제공하며, with는 확장 함수가 아닌 유일한 함수로서 특별한 위치를 차지합니다.

함수접근반환확장?일반적인 시나리오
letit람다 결과변환, null 검사
runthis람다 결과컨텍스트를 사용한 계산
withthis람다 결과아니오호출 그룹화
applythis컨텍스트 객체속성 초기화
alsoit컨텍스트 객체부작용, 로깅

새 값을 반환하지 않고 객체를 구성하려면 apply(this를 통한 접근) 또는 also(it를 통한 접근)를 사용하세요. 객체를 기반으로 새 값을 계산하려면 let(it를 통한 접근) 또는 run(this를 통한 접근)을 사용하세요. 체인 없이 호출을 그룹화하려면 with를 사용하세요. 이 방식을 따르면 Kotlin에 익숙한 다른 개발자들에게 코드가 예측 가능해집니다.

apply와 also: 객체 반환을 통한 구성

apply는 컨텍스트 객체를 반환하고 this를 통한 접근을 제공하는 스코프 함수입니다. 이는 생성 후 객체 속성을 초기화하기 위한 이상적인 도구입니다. apply 블록 내에서는 객체 이름을 반복하지 않고 속성을 설정할 수 있습니다. 메서드는 객체 자체를 반환하므로 apply를 체인에 포함시키거나 초기화자에서 사용할 수 있습니다.

kotlin
data class ServerConfig(
    var host: String = "localhost",
    var port: Int = 8080,
    var useTls: Boolean = false
)

val config = ServerConfig().apply {
    host = "api.example.com"
    port = 443
    useTls = true
}

목록에서 apply는 this를 통해 직접 속성에 접근하여 ServerConfig를 구성합니다(this는 생략됨). apply가 없으면 config.host = ..., config.port = ...를 작성해야 합니다 — 동일한 변수에 대한 세 번의 반복 참조입니다. 객체를 반환하면 구성 결과를 val config에 저장할 수 있습니다. also는 apply와 달리 it를 통해 객체를 전달하며 부작용에 적합합니다.

kotlin
fun saveUser(user: User) {
    validate(user).also { result ->
        println("검증 결과: $result")
    }
    val savedUser = user.also {
        log("Saving user ${it.id}")
        database.save(it)
    }
}

예제에서 also는 로깅에 사용됩니다 — 원래 객체를 반환하면서 객체를 수정하지 않고 부작용(메시지 출력)을 수행합니다. 이는 체인입니다: validate(user)가 User를 반환하고, also가 결과를 로깅하며 사용자를 전달합니다. also는 컬렉션에 요소를 추가하거나 변환 체인 중간에서 디버깅하는 데도 유용합니다.

let과 run: 변환 및 계산

let은 람다 결과를 반환하고 it를 통해 컨텍스트를 전달하는 스코프 함수입니다. 이는 null 안전 변환을 위한 기본 함수입니다: 객체가 nullable인 경우, ?.let { } 조합은 null이 아닌 값에 대해서만 블록을 실행합니다. let은 임시 변수의 스코프를 제한하고 한 유형에서 다른 유형으로의 map-유사 변환에도 사용됩니다.

kotlin
fun findUser(id: Int): User?

val displayName = findUser(42)?.let { user ->
    "${user.name} (${user.email})"
} ?: "Unknown user"

// 컬렉션 변환과 함께 사용하는 let
val numbers = listOf("1", "2", "3")
val parsed = numbers.firstOrNull()?.let {
    it.toIntOrNull()
} ?: 0

첫 번째 예제에서 let은 ?.를 통해 호출됩니다 — 블록은 findUser가 null이 아닌 값을 반환한 경우에만 실행됩니다. 람다는 it를 통해 user를 받고(명확성을 위해 이름 변경 가능) 포맷된 문자열을 반환합니다. 사용자를 찾을 수 없는 경우, Elvis 연산자 ?:가 기본값을 제공합니다. 두 번째 예제에서 let은 문자열을 잠재적 null과 함께 숫자로 변환합니다.

run은 this를 통한 접근을 가진 let의 유사체로, 람다 결과를 반환합니다. run은 객체 컨텍스트가 필요하지만 새 값을 반환하는 계산에 편리합니다. 객체 없이 run()을 호출하면(run { ... }으로) 변수에 대한 임시 스코프가 생성됩니다. with는 this를 통한 접근을 가진 비-확장 함수로, 체인 없이 호출을 그룹화하는 데 적합합니다.

kotlin
// 컨텍스트 기반 계산으로서의 run
val transformed = listOf(1, 2, 3).run {
    filter { it > 1 }.map { it * 10 }
}
println(transformed) // [20, 30]

// 호출을 그룹화하는 with
val info = with(StringBuilder()) {
    append("Name: ")
    append("Alice")
    toString()
}

예제에서 리스트에 대한 run은 필터링 및 매핑의 결과를 반환합니다 — 변환 자체이지 리스트가 아닙니다. with는 StringBuilder를 인수로(점을 통해가 아니라) 받아 내부에서 this와 함께 작업합니다: append, append, toString. with의 결과는 info 문자열입니다. run과 with 사이의 선택은 종종 주관적이지만, 객체가 체인 없이 다른 곳에서 전달되는 경우 with가 선호됩니다.

with: 확장 없는 컨텍스트

with는 확장 함수가 아니라는 점에서 다른 스코프 함수와 다릅니다. 객체를 첫 번째 인수로, 람다를 두 번째 인수로 받습니다. 람다 내부에서 객체는 this를 통해 접근 가능합니다. with는 결과를 저장하지 않고 객체 메서드 호출을 그룹화하거나 여러 속성을 읽기 위해 일시적으로 컨텍스트에 “들어”가야 할 때 편리합니다.

kotlin
val user = User("Alice", "alice@example.com", "Admin")

val summary = with(user) {
    "User $name has role $role and email $email"
}
println(summary)

// UI 컴포넌트 초기화를 위한 with
with(TextView(context)) {
    text = "Hello"
    textSize = 18.0f
    setTextColor(Color.BLUE)
}

첫 번째 예제에서 with는 this를 통해 직접 user 속성에 접근하여 summary 문자열을 형성합니다. with가 없으면 “User ${user.name} has role ${user.role}”을 작성해야 합니다 — user의 반복입니다. 두 번째 예제에서 with는 TextView 구성을 그룹화합니다: 모든 메서드와 속성이 반복 없이 하나의 객체에서 호출됩니다. with의 단점 — 확장 함수가 아니고 컨텍스트 객체를 반환하지 않으므로 체인에서 사용할 수 없습니다.

자주 묻는 질문

객체 초기화에 어떤 스코프 함수를 선택해야 하나요?

apply를 사용하세요 — 객체를 반환하고 this를 통한 접근을 제공하여 객체 이름을 반복하지 않고 속성을 설정할 수 있습니다. also는 객체 속성과 구별하기 위해 명시적 it 매개변수가 필요한 경우 적합합니다.

let과 run의 차이점은 무엇인가요?

let은 it(명시적 매개변수)를 통해 컨텍스트를 전달하고, run은 this(암시적 수신자)를 통해 전달합니다. let은 null 검사와 변환에 편리하고, run은 컨텍스트를 사용한 계산에 적합합니다. 둘 다 람다 결과를 반환합니다.

apply 대신 with를 언제 사용하나요?

with는 확장 함수가 아니라 객체를 인수로 받습니다. 체인이 필요하지 않을 때 호출을 그룹화하는 데 with를 사용하세요. apply는 객체를 반환하는 확장 함수로, 초기화자와 빌더 패턴에 편리합니다.

스코프 함수를 다른 스코프 함수 안에 중첩할 수 있나요?

네, 하지만 this에 주의하세요 — 중첩된 this는 혼란을 야기합니다. 외부 객체를 참조할 때 모호함을 피하기 위해 중첩된 컨텍스트에는 명시적 이름을 가진 let 또는 also를 사용하세요.

가장 성능이 좋은 스코프 함수는 무엇인가요?

모든 스코프 함수는 inline이므로 익명 클래스로 인한 오버헤드가 없습니다. 이들 간의 성능 차이는 미미합니다. 선택은 속도가 아니라 가독성과 관례에 기반해야 합니다.

요약

  • 스코프 함수 — 객체 컨텍스트에서 코드를 실행하기 위한 다섯 가지 Kotlin 인라인 함수(let, run, with, apply, also)
  • apply는 this를 통한 접근으로 컨텍스트 객체 반환 — 속성 초기화에 이상적
  • also는 it를 통한 접근으로 컨텍스트 객체 반환 — 로깅 및 부작용에 적합
  • let은 it를 통한 접근으로 람다 결과 반환 — null 안전 변환의 기초
  • run은 this를 통한 접근으로 람다 결과 반환 — 컨텍스트를 사용한 계산에 편리
  • with는 확장 함수가 아니며 람다 결과 반환 — 체인 없이 호출 그룹화에 적합
  • 특성의 조합(this/it 및 객체/결과 반환)이 각 작업에 대한 스코프 함수 선택을 결정

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기