범위 지정 함수(Scope function)란?
범위 지정 함수는 특정 객체에 대한 작업을 블록 안에 넣어 실행할 수 있도록 하는 함수이다. 블록은 특정 객체에 대해 할 작업의 범위가 되며, 따라서 범위 지정 함수라 부른다. 특정 객체에 대한 작업을 블록안에 넣게 되면 가독성이 증가하여 유지 보수가 쉬워진다. 코틀린에서는 let, run, apply, also, with 총 5가지 기본적인 범위 지정함수를 지원한다.,
코틀린의 범위 지정 함수
1. apply
2. run
3. with
4. let
5. also
범위 지정함수와 수신객체 지정 람다(함수)
범위 지정함수는 다른 말로 수신객체 지정 람다(함수)라고도 부른다. 이유는 수신객체를 명시하지 않거나 it을 호출하는 것만으로 람다 안에서 수신 객체의 메서드를 호출할 수 있도록 해주기 때문이다. 이것이 가능한 이유는 블록(block)람다식에서 수신 객체를 람다의 입력 파라미터 혹은 수신 객체로 사용하였기 때문이다.
범위 지정함수(apply, with, let, also, run)은 언제 사용해야 하는가?
apply
apply는 수신객체 내부 프로퍼티를 변경한다음 수신객체 자체를 반환하기 위해 사용하는 함수이다. 따라서 객체 생성 시에 다양한 프로퍼티를 설정해야 하는 경우 자주 사용된다.
apply에서의 block은 람다식의 수신객체로 (T)를 지정하기 때문에 람다식 내부에서 수신객체에 대한 명시를 하지 않고 함수를 호출할 수 있게 된다.
apply는 다음과 같은 경우에 사용한다.
- 람다 함수 내에서는 객체 이름 명시 없이 프로퍼티와 함수 직접 호출이 가능하므로, 프로퍼티에 값을 할당할 때 유용 ex) 객체 초기화
public inline fun <T> T.apply(block: T.() -> Unit): T
val person = Person().apply {
name = "DevJtm"
age = 28
temperature = .36.2f
}
apply를 활용하면 위의 방법으로 수신객체의 프로퍼티 지정이 가능하다. 람다식의 수신 객체가 apply의 수신객체이기 때문에 수신객체에 대한 명시를 생략하는 것이 가능하다.
run
run은 apply와 동일하게 동작하지만 수신객체를 return하지 않고, run 블록의 마지막 라인을 return하는 범이 지정 함수이다. 이는 수신 객체에 대해 특정한 동작을 수행한 후 결과 값을 리턴받아야 할 때 사용한다.
run은 다음과 같은 경우에 사용한다.
- 람다에 객체 초기화와 반환 값 계산이 모두 포함될 때
public inline fun <T, R> T.run(block: T.() -> R): R
fun main() {
val person = Person(name = "Devjtm", age = 28, temperature = 36.5f)
val isPersonSick = person.run{
temperature - 37.2f
true //return 값
}
}
with
with는 수신객체에 대한 작업 후 마지막 라인을 return한다. run과 완전히 동일하게 동작한다. 다른 점 하나는 run은 확장 함수로 사용되지만 with은 수신객체를 파라미터로 받아 사용한다는 점이다. run을 사용하는 것이 깔끔하므로 실제로는 사용되지 않는다.
with은 다음과 같은 경우에 사용한다.
- 한 객체의 멤버에 반복해서 접근할 때 객체명을 일일히 명시하지 않고 멤버에 바로 접근 가능하며, 결과가 필요하지 않을 때 유용
- 안전한 호출(?.)을 지원하지 않으므로, 널 값이 아닌 것으로 확인된 객체에 이 함수를 사용해야 함
public inline fun <T, R> with(receiver: T, block: T.() -> R): R
fun main(){
val person = Person(name = "Devjtm", age = 28, temperature = 36.5f)
val isPersonSick = with(person){
temperature = 38.0f
true //return 값
}
}
let
let은 수신객체를 이용해 작업을 한 후 마지막 줄을 return 할 때 사용한다. run이나 with과는 수신객체를 접근할 때 it을 사용해야 한다는 점만 다르고 나머지 동작은 같다. 하지만 실제 사용에서는 조금 차이가 있다. 아래에서 어떤 차이가 있는지 알아보자.
let은 다음과 같은 경우에 사용한다.
- null check 후 코드를 실행해야 하는 경우
- nullable한 수신 객체를 다른 타입의 변수로 변환해야 하는 경우
- 단일 지역 변수의 범위를 제한하는 경우
요약하면 nullable한 값을 처리해야 할 때는 let을 사용 해야 한다.
let을 이용해 null을 check를 하려면 아래와 같이 null check 연산자인 '?'와 함께 사용해야 한다. '?.let'을 사용하게 돠면 let의 block은 수신객체가 null이 아닐 때만 수행된다. 따라서 let block에서의 it의 타입은 nullable하지 안은 타입이 된다.
public inline fun <T, R> T.let(block: (T) - >R): R
fun main() {
var person: Persion? =null
val isReserved = person?.let { it: Person ->
reserveMovie(it)
}
}
also
also는 apply와 마찬가지로 수신객체 자신을 반환한다. apply가 프로퍼티를 세팅 후 객체 자체를 반환 하는데만 사용된다면, also는 프로퍼티 세팅 뿐만 아니라 객체에 대한 추가적인 작업(디버그, 로깅, 유효성 검사 등)을 한 후 객체를 반환할 때 사용된다.
also에서의 block은 람다식의 입력 파라미터로 also의 수신객체(T)를 지정하기 때문에 내부에서 수신 객체를 사용하기 때문에 it을 사용해야 한다.
public inline fun <T> T also(block: (T) -> Unit): T
val numbers = mutableListOf("one", "two", "three")
numbers
.also { println("The list elements before adding new one: $it") }
.add("four")
also는 다음과 같은 경우에 사용한다.
- 디버그 정보 로깅 또는 인쇄와 같이 오브젝트를 변경하지 않는 추가 조치에 사용
참고 자료
https://salix97.tistory.com/224
[Kotlin] 코틀린 범위 지정 함수 let, with, run, apply, also
코틀린 표준 라이브러리는 간결하고 명료한 코드를 작성하는 데 도움을 주는 확장 함수(extension function)들을 제공한다. 확장함수는 람다(lamda) 를 인자로 받아 동작하며, 확장함수를 실행하는 주
salix97.tistory.com
https://jinee0717.tistory.com/11
[kotlin] 코틀린을 코틀린답게 (라이브러리 - 스트림 함수,범위 지정 함수)
스트림 함수 컬렉션에 포함된 자료의 타입 변경 또는 새로운 자료 추가 생성을 쉽게 구현하기 위해 제공되는 함수 변환 map() : 컬렉션 내 인자를 함수에 정의된 규칙에 따라 다른 값 혹은 타입으
jinee0717.tistory.com
'Kotlin' 카테고리의 다른 글
[Kotlin] Object 키워드 (with companion object) (0) | 2024.11.02 |
---|---|
[Kotlin] Data Class란? (3) | 2024.11.02 |
[Kotlin] Sealed Class란? (2) | 2024.11.02 |
[Kotlin] 늦은 초기화 (lateinit, by lazy) (0) | 2023.08.22 |
[Kotlin] 필드(Field)와 프로퍼티(Property) (0) | 2023.08.22 |