🎪 스코프 함수
📖 스코프 함수란?
스코프 함수는 객체의 컨텍스트 내에서 코드 블록을 실행하는 함수입니다. 객체를 더 간결하게 다룰 수 있습니다.
💡 5가지 스코프 함수
let - 객체를 it으로 받아 결과 반환
apply - 객체를 this로 받아 객체 자체 반환 (초기화)
run - 객체를 this로 받아 결과 반환
also - 객체를 it으로 받아 객체 자체 반환 (부가 작업)
with - 객체를 this로 받아 결과 반환 (확장 함수 아님)
🔧 let
기본 사용
fun main() {
val name = "홍길동"
val result = name.let {
println("이름: $it")
it.length // 반환값
}
println("길이: $result") // 길이: 3
}
null 체크
fun main() {
val name: String? = "홍길동"
// null이 아닐 때만 실행
name?.let {
println("이름: $it")
println("길이: ${it.length}")
}
}
지역 변수 대신
fun main() {
// ❌ 지역 변수 사용
val numbers = listOf(1, 2, 3, 4, 5)
val result = numbers.filter { it > 2 }
println(result)
// ✅ let 사용 (더 간결)
listOf(1, 2, 3, 4, 5)
.filter { it > 2 }
.let { println(it) }
}
🎨 apply
객체 초기화
data class Person(var name: String = "", var age: Int = 0)
fun main() {
val person = Person().apply {
name = "홍길동" // this.name
age = 25 // this.age
}
println(person) // Person(name=홍길동, age=25)
}
빌더 패턴
class StringBuilder {
private val sb = StringBuilder()
fun append(text: String) = apply {
sb.append(text)
}
fun appendLine(text: String) = apply {
sb.appendLine(text)
}
override fun toString() = sb.toString()
}
fun main() {
val text = StringBuilder()
.append("안녕하세요")
.appendLine("!")
.append("반갑습니다")
.toString()
println(text)
}
🚀 run
객체 초기화 + 결과 반환
data class Person(var name: String = "", var age: Int = 0)
fun main() {
val greeting = Person().run {
name = "홍길동"
age = 25
"안녕하세요, ${name}님! (${age}세)" // 반환값
}
println(greeting) // 안녕하세요, 홍길동님! (25세)
}
코드 블록 실행
fun main() {
val result = run {
val a = 10
val b = 20
a + b // 반환값
}
println(result) // 30
}
🎯 also
부가 작업 (로깅 등)
data class Person(val name: String, val age: Int)
fun main() {
val person = Person("홍길동", 25)
.also { println("생성됨: $it") }
.also { println("확인 완료") }
println(person)
}
체이닝 중간 로그
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
.filter { it % 2 == 0 }
.also { println("짝수: $it") } // 중간 확인
.map { it * it }
.also { println("제곱: $it") } // 중간 확인
println("최종: $numbers")
}
🌟 with
여러 메서드 호출
fun main() {
val numbers = mutableListOf(1, 2, 3)
with(numbers) {
add(4)
add(5)
remove(1)
println("크기: $size")
}
println(numbers) // [2, 3, 4, 5]
}
결과 반환
data class Person(val name: String, val age: Int)
fun main() {
val person = Person("홍길동", 25)
val info = with(person) {
"이름: $name, 나이: $age"
}
println(info) // 이름: 홍길동, 나이: 25
}
🎯 실전 예제
API 요청 처리
data class User(val id: Int, val name: String, val email: String?)
fun main() {
val user = User(1, "홍길동", null)
// let으로 null 체크
user.email?.let { email ->
println("이메일 전송: $email")
} ?: println("이메일 없음")
}
객체 설정
class Config {
var host: String = ""
var port: Int = 0
var timeout: Int = 0
fun connect() {
println("연결: $host:$port (timeout: ${timeout}ms)")
}
}
fun main() {
Config().apply {
host = "localhost"
port = 8080
timeout = 3000
}.connect()
}
파일 처리 시뮬레이션
class File(val path: String) {
fun read(): String = "파일 내용"
fun close() = println("파일 닫힘")
}
fun main() {
val content = File("test.txt").run {
val data = read()
close()
data // 반환
}
println(content)
}
📊 비교표
참조 방식
fun main() {
val name = "Kotlin"
// it으로 참조
name.let { println(it) }
name.also { println(it) }
// this로 참조 (생략 가능)
name.apply { println(this) }
name.run { println(this) }
with(name) { println(this) }
}
반환값
fun main() {
val name = "Kotlin"
// 결과 반환
val length1 = name.let { it.length } // 6
val length2 = name.run { length } // 6
val length3 = with(name) { length } // 6
// 객체 자체 반환
val name1 = name.apply { } // "Kotlin"
val name2 = name.also { } // "Kotlin"
}