# 스코프 함수
- 스코프 함수(Scope Function)는 코드를 축약해서 표현할 수 있도록 도와주는 함수이다
-
영역 함수라도고 한다.
-
사용법은 함수처럼 쓰지 않고 run, let처럼 괄호 없이 일종의 키워드 같이 사용할 수 있다.
-
lateinit과 함께 Safe Call 남용을 막아주는 역할도 하기 때문에 많이 사용하는 요소이다.
- 스코프 함수에는 run, let, apply, also, with이 있다.
# run과 let으로 보는 스코프 함수
- run과 let은 자신의 함수 스코프(코드 블록) 안에서 호출한 대상을 this와 it로 대체해서 사용할 수 있다.
# run
- 스코프 함수 안에서 호출한 대상을 this로 사용할 수 있다.
-
클래스 내부의 함수를 사용하는 것과 동일한 효과이기 때문에 this는 생략하고 메서드나 프로퍼티를 바로 사용할 수 있다.
-
다음 예제에서는 MutableList를 run 함수를 사용해서 스코프를 지정한 후 내부에서 size 프로퍼티를 직접 호출하였다.
var list = mutableListOf("Scope", "Function")
list.run {
val listSize = size
println("list의 길이 run = $listSize")
}
# let
-
함수 영역 안에서 호출한 대상을 it으로 사용할 수 있습다.
-
it을 생략할 수는 없지만, target 등 다른 이름으로 바꿀 수 있다.
-
다음 예제에서는 MutableList의 size 속성을 let 스코프 안에서 it.size로 호출하였다.
var list = mutableListOf("Scope", "Function")
list.let { // it -> 생략된 형태. it -> 대신에 target -> 등으로 변경 가능합니다.
val listSize = it.size // 모든 속성과 함수를 it.멤버로 사용할 수 있습니다.
println("리스트의 길이 let = $listSize")
}
# this와 it으로 구분하기
- 위에서 봤듯이 스코프 함수는 자신을 호출한 대상을 this 또는 it으로 대체해서 사용할 수 있는데, 나머지 스코프 함수의 사용법을 두 가지로 구분해서 알아보겠다.
# this로 사용되는 스코프 함수: run, apply, with
- 다음은 apply와 with의 사용 예제다. 스코프 함수 안에서 this로 사용되기 때문에 메서드나 프로퍼티를 직접 호출한다. (예제 코드에서는 this를 생략했다 - 원랜 this.size)
var list = mutableListOf("Scope", "Function")
list.apply {
val listSize = size
println("리스트의 길이 apply = $listSize")
}
with (list){
val listSize = size
println("리스트의 길이 with = $listSize")
}
# 여기서 잠깐!!
- 호출 대상이 null일 경우
-
with는 스코프 함수이긴 하지만 위의 2개와는 다르게 확장(Extension) 함수가 아니기 때문에 일반 함수처럼 사용된다.
-
따라서 호출하는 대상이 null일 경우에는, with보다는 apply나 run을 사용하는 것이 효율적이다.
target?.apply { /* 코드 */ }
# it으로 사용되는 스코프 함수: ley, also
- 다음은 let과 also를 사용하는 예제이다
var list = mutableListOf("Scope", "Function")
list.let { target -> // it을 target 등과 같이 다른 이름으로 변경 가능합니다.
val listSize = target.size // target으로 변경했기에 멤버 접근은 target.속성 입니다.
println("리스트의 길이 let = $listSize")
}
list.also {
val listSize = it.size
println("리스트의 길이 also = $listSize")
}
# 반환값으로 구분하기
-
위에서 사용해본 것만으로는 this와 it으로 사용되는 함수가 2개 이상씩 중복으로 있는 것처럼 보일 수 있다.
-
하지만 동일하게 this로 사용되는 함수라도 대입 연산자를 사용해서 값을 반환할 경우에는 용도가 달라지게된다.
-
결괏값을 반환할 경우, 스코프가 종료되는 시점에서의 반환값이 다르기 때문에 서로 다른 역할을 하는 스코프 함수가 필요하다.
# 호출 대상인 this 자체를 반환하는 스코프 함수: apply, also!!
-
apply를 사용하면 스코프 함수 안에서 코드가 모두 완료된 후 자기 자신을 되돌려 준다.
-
다음 예제에서 apply 스코프의 마지막 줄에서 count()를 호출했지만, 마지막 코드와 상관없이 그냥 MutalbeList 자신을 돌려주기 때문에 Scope, Function에 Apply가 추가된 값이 출력된다.
-
also 또한 동일하게 동작한다.
var list = mutableListOf("Scope", "Function")
val afterApply = list.apply {
add("Apply")
count()
}
println("반환값 apply = $afterApply") // 반환값 apply = [Scope, Function, Apply]
val afterAlso = list.also {
it.add("Also")
it.count()
}
println("반환값 also = $afterAlso") // 반환값 also = [Scope, Function, Apply, Also]
# 마지막 실행 코드를 반환하는 스코프 함수 : let, run,with!!
-
let, run, with의 결괏값을 반환하는 경우에는 앞의 2개와는 완전히 다른 결과가 나올 수 있으므로 주의해야 한다.
-
자기 자신이 아닌 스코프의 마지막 코드를 반환하기 때문이다.
-
다음 예제의 let에서 스코프 마지막 코드가 it.count()로 종료되었다.
-
apply나 also라면 마지막 코드에 상관없이 Scope, Function, Run이 출력되지만, let은 마지막 코드가 반환되기 때문에 출력값으로 리스트의 개수인 3이 출력된다.
-
run과 with도 마지막 코드가 반환된다.
var list = mutableListOf("Scope", "Function")
val lastCount = list.let {
it.add("Run")
it.count()
}
println("반환값 let = $lastCount") // 반환값 let = 3
val lastItem = list.run {
add("Run")
get(size-1)
}
println("반환값 run = $lastItem") // 반환값 run = Run
val lastItemWith = with(list){
add("With")
get(size-1)
}
println("반환값 with = $lastItemWith") // 반환값 with = With
'개발 노트 > Kotlin' 카테고리의 다른 글
[Android/Kotlin] 파이어베이스 CRUD 만들기 (1) - 프로젝트 생성, 파이어베이스 연동 (0) | 2024.01.26 |
---|---|
[Kotlin]BottomNavigation (0) | 2024.01.18 |
[kotlin]지연 초기화 (0) | 2024.01.16 |
[kotlin]null 값에 대한 안정적인 처리 - Null Safety (0) | 2024.01.16 |
[kotlin]클래스와 설계 (0) | 2024.01.16 |