[코틀린] 범위 지정 함수 let(), apply(), with(), run(), also()

2021. 9. 3. 14:23바삭바삭 IT/코틀린

코틀린에서 아주 자주 볼 수 있는 범위지정함수 5가지를 정리합니다. 

범위 지정 함수는 코틀린에서 표준 라이브러리를 통해 제공하고 있습니다.

  • let() 
  • apply()
  • with()
  • run()
  • also()

let()

let()은 이 함수를 호출한 객체를 이어지는 함수 블록의 인자로 전달합니다. 

//1. 이 함수를 호출한 객체를 block의 인자로 전달하고 block의 결과를 반환 
fun <T,R> T.let(block: (T) -> R): R

let은 불필요한 변수 선언을 방지할 수 있습니다. 

//let 사용 전
val file = File(path)
if(!file.exists()){
	throw FileNotFoundException(file.toString())
}
val metadata = loadModuleMetadata(file)


//let 사용 후
File(path).let {
  if (!it.exists()) {
  throw FileNotFoundException(it.toString())
  }
	val metadata = loadModuleMetadata(it)
}

또, let()은 간단하게 null을 체크하고 싶을 때 유용합니다.

//message가 null이 아닌 경우에만 let 함수 호출
message?.let{
	showToast(message)
}

apply()

apply()는 이 함수를 호출한 객체를 이어지는 함수 블록의 리시버로 전달합니다.  

//1. 이 함수를 호출한 객체를 block의 리비서로 전달하고 함수를 호출한 객체를 반환
fun <T> T.apply(block: T.() -> Unit): T

객체의 속성을 수정할때 매번 일일이 객체 이름을 명시하지 않아도 되어 코드를 간략히 줄일 수 있습니다. 

//apply 적용 전
private val cal = Calendar.getInstance()
cal.set(YEAR, 1998)
cal.set(MONTH, SEPTEMBER)
cal.set(DAY_OF_MONTH, 4)

//apply 적용 후
private val cal = Calendar.getInstance().apply {
        set(YEAR, 1998)
        set(MONTH, SEPTEMBER)
        set(DAY_OF_MONTH, 4)
}

with()

with()는 인자로 받은 객체를 이어지는 함수 블록의 리시버로 전달합니다.

//1. 인자 reciever를 이어지는 함수 block의 리시버로 전달, block의 결과를 반환 
fun <T,R> with(receiver: T, block: () -> R): R

null이 아닌지 확인된 객체에 이 함수를 사용하는 것이 좋습니다.

with(viewModel) {
  if (isFiltered()) {
  	clearGrowZoneNumber()
  } else {
  	setGrowZoneNumber(9)
  }
}

run()

run()은 아래 선언된 두가지 형태로 사용할 수 있습니다. 2번은 얼핏 apply와 비슷해 보이는데요. 차이점은 apply는 호출한 '주체'인 객체를 반환하는 반면, run은 block의 '결과'를 반환합니다.

//1. 함수형 인자 block을 호출하고 결과를 반환
fun <R> run(block: () -> R): R

//2. 이 함수를 호출한 객체를 block의 리비서로 전달하고 결과를 반환
fun <T, R> T.run(block: T.() -> R): R

1번처럼 익명함수처럼 사용할 경우, 복잡한 계산을 위해 임시 변수가 필요할때 유용합니다.

val padding = run {
	val defaultPadding = 10
    val extraPadding = 5
    
    defaultPadding + extraPadding
}

2번의 run은 안전한 호출을 사용할 수 있어서 null값일 수 있는 객체의 속성이나 함수에 연속적으로 접근할 때 유용합니다.

lastInitialView?.run {
  setText(player.lastInitial)
  requestFocus()
  setSelection(length())
}

also()

also()는 이 함수를 호출한 객체를 block의 인자로 전달하고, 함수를 호출한 객체를 반환한다.

fun T.also(block: (T) -> Unit): T

also()는 주로 객체의 속성을 바꾸지 않고 사용할 때 유용하다.

val extras = Bundle().also {
	val position = preferences.getLong(KEY, 0L)
	it.putLong(POSITION, position)
}

 


위 내용을 정리하면 아래와 같습니다.

범위 지정 함수 input return 확장 함수인가? 사용목적
let() Parameter (it) 람다함수 result Y null이 아닌 객체에 람다를 실행하고 싶을때
apply() Reciever (this) apply를 호출한 객체 자신 Y 객체의 여러 속성들을 설정할때
with() Reciever (this) 람다함수 result N 객체에 대해 그룹화 함수를 호출하고 싶을때
run() - 1 None 람다함수 result N 정규식 필요한 명령을 실행하고 싶을때
run() - 2 Reciever (this) 람다함수 result Y 객체의 여러 속성들을 설정하고 결과를 반환하고 싶을 때
also() Parameter (it) also를 호출한 객체 자신 Y 추가적인 영향을 주고싶을때

 

참고 : https://kotlinlang.org/docs/scope-functions.html

반응형