! 스코프 함수는 매번 쓸 때마다 apply? run? with? 무엇을 써야할지 헷갈린다. 이번 기회에 확실히 공부해서 정리하고자 한다.
코틀린의 표준 라이브러리에서 '스코프 함수'라는 것을 제공해준다. 스코프 함수란
특정 객체의 컨텍스트 안에서 특정 동작(속성 초기화, 활용 등)을 실행하기 위한 목적 만을 가진 함수
이 스코프 함수를 람다 함수로 사용할시 스코프를 형성하게 되는데 이 스코프 내에서는 객체의 이름을 참조할 필요 없이 객체에 접근하고 핸들링하기 편하게끔 해준다.
apply, run, with, also, let이 있고 이제 이것들에 대해 자세히 알아보자!
data class Member(val name : String, var age: Int)
inline fun <T> T.apply(block : T.() -> Unit): T {
block()
return this
}
객체를 새로 생성하고 특정 변수에 할당하기 전에 초기화 작업을 하는 스코프를 만든다
apply 함수 내에 모든 명령들이 수행되고 나면 명령들이 적용되어 새로 생성된 객체를 반환
반환 결과가 객체 자신!
확장 함수이기 때문에 객체 컨텍스트를 receiver(this)로 이용이 가능하다.
실행결과 : 이벤트 아메리카노의 500원
inline fun <T,R> T.run(block : T.() -> R) : R {
return block()
}
apply와 명확하게 다른 점이 반환하는 값이 객체가 아닌 스코프 내에 실행된 값이다
그러므로 특정 객체의 프로퍼티를 출력하거나 계산값으로 활용하는 등의 핸들링을 할 때 사용한다.
확장함수 이기 때문에 apply와 마찬가지로 receiver(this)로 이용이 가능하다.
safe call(.?)을 붙여 non-null일 때만 실행이 가능하다.
반환하는 값이 객체가 아니라 스코프내에서 실행된 this.price + 3000의 값이 나온다.
inline fun <T, R> with(receiver : T, block: T.() -> R) : R{
return receiver.block()
}
확장 함수가 아니므로 컨텍스트 객체를 argument로 전달하며 람다의 내부에서는 확장함수로 적용되어 receiver(this)로 사용이 가능하다!
특징 및 동작은 위의 run과 동일하다!
val member = Member("hotaek", 26)
with(member) {
println("$name")
println("$age")
}
실행 결과 : hotaek, 26
inline fun <T> T.also(block: (T) -> Unit) : T {
block(this)
return this
}
also는 apply와 동일하게 생성된 인스턴스를 반환한다.
it을 사용해 프로퍼티에 접근이 가능하다.
객체의 프로퍼티를 전혀 사용하지 않거나 변경하지 않고 사용하는 경우에 유용하다
예를 들면, 객체의 데이터 유효성 확인, 디버그, 로깅 등의 부가적인 목적으로 사용함
inline fun<T,R> T.let(block : (T) -> R) : R{
return block(this)
}
let은 run과 동일하게 최종 실행 결과를 반환한다.
it을 사용해 프로퍼티에 접근이 가능하다.
지정된 값이 null이 아닌 경우에 코드를 실행해야 하는 경우 및 nullable 객체를 다른 nullable 객체로 변환하는 경우 사용한다.