Skip to content

Latest commit

 

History

History
140 lines (92 loc) · 5.59 KB

범위 지정 함수.md

File metadata and controls

140 lines (92 loc) · 5.59 KB

범위 지정 함수

코틀린에서 제공하는 여러 함수들 중 유용하게 사용할 수 있는 함수들이다.

let()

let()은 함수를 호출하는 객체를 이어지는 블록의 인자로 넘기고, 블록의 결과값을 반환한다.

fun<T,R> T.let(block: (T) -> R): R
  • 사용 예

함수를 호출한 객체를 인자로 받으므로, 이를 사용하여 다른 메소드를 실행하거나 연산을 수행해야 하는 경우 사용할 수 있다.

커스텀 뷰에서 Padding 값을 지정할 때 일반적으로는 아래와 같이 코드를 작성한다.

val padding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
16f, resources.displayMetrics).toInt()

setPadding(padding, 0, padding, 0)

위의 코드에서 padding이라는 상수 값은 한 번만 사용되고 더 이상 사용되지 않는다. 이런 경우, 다음과 같이 let()을 사용하면 불필요한 선언을 방지할 수 있다.

TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
16f, resources.displayMetrics).toInt().let{ padding->
	setPadding(padding, 0, padding, 0)
}

계산된 값을 padding 이라는 이름의 인자로 받아서 let{..} 블록 안에서 값을 세팅한다.

람다식의 인자가 한 개일 경우, 인자 이름을 생략하고 it 을 사용하여 코드를 간략하게 할 수 있다.

또한, let()을 안전한 호출 ?. 연산자와 함께 사용하면 if(null !=obj) ... 를 대체할 수 있다. → 널 값에 대한 유효성 검사를 대신할 수 있다.

var obj: String?

if(obj != null ) {
	println("null이 아니에요~")
}

obj?.let {
	println("null이 아니에요~")
}

let()을 이용한 코드는 obj가 null이 아닐 경우 작업을 수행하는 코드이다.

apply()

apply()는 함수를 호출하는 객체를 이어지는 블록의 리시버 로 전달하고, 객체 자체를 반환한다.

  • 리시버란? 바로 이어지는 블록 내에서 메소드 및 속성에 바로 접근할 수 있도록 할 객체를 의미한다.(접근 제어자에 따라 접근 가능한 범위에 한함.)

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

  • 사용 예

특정 객체를 생성하면서 함께 호출해야 하는 초기화 코드가 있는 경우 사용할 수 있다.

새로운 LayoutParams 객체를 생성하고 속성을 지정하는 코드를 예로 들어보자. 여러 줄에 걸쳐 새로 선언한 변수 param을 사용하여 속성을 지정하고 있다.

val param = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT)
param.gravity = Gravity.CENTER_HORIZONTAL
param.weight = 1f
param.topMargin = 100
param.bottomMargin = 100

위의 코드를 apply() 함수를 사용하면 이를 다음과 같이 바꿀 수 있다. param을 사용하지 않고 직접 속성을 지정할 수 있다.

val param = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT).apply{
	gravity = Gravity.CENTER_HORIZONTAL
	weight = 1f
	topMargin = 100
	bottomMargin = 100
}

run()

run() 함수는 인자가 없는 익명 함수처럼 동작하는 형태와 객체에서 호출하는 형태 두 가지가 있다. 객체 없이 run() 함수를 사용하면 인자 없는 익명 함수처럼 사용할 수 있다. 이어지는 블록 내에서 처리할 작업들을 넣어줄 수 있으며, 일반 함수와 마찬가지로 값을 반환하지 않거나(Unit) 특정 값을 반환할 수도 있다.

인자가 없는 익명 함수처럼 사용하는 경우

  • 어떤 값을 계산할 필요가 있거나 지역변수의 범위를 제한하기 위해 사용한다.

    fun run(block: () -> R): R

객체에서 run() 함수를 호출할 경우

  • 호출하는 객체를 이어지는 블록의 리시버로 전달하고, 블록의 결과값을 반환한다.

    fun <T,R> T.run(block: T.() -> R): R

  • 사용 예

객체에서 이 함수를 호출하는 경우 객체를 리시버로 전달받으므로, 특정 객체의 메소드나 필드를 연속적으로 호출하거나 값을 할당할 때 사용한다.

apply() 와 적용 예가 유사하지만, apply()는 새로운 객체를 생성함과 동시에 연속된 작업이 필요할 때 사용하고 run() 은 이미 생성된 객체에 연속된 작업이 필요할 때 사용한다는 점이 조금 다르다.

다음은 AppCompatActivity의 액션바 속성을 연속하여 변경하는 예이다. run() 메소드에서도 안전한 호출 ?. 를 사용할 수 있으며, 이를 통해 액션바가 null이 아닐 경우에만 블록 내 명령들이 실행된다.

supportActionBar?.run{
	setDisplayHomeAsUpEnabled(true)
	setHomeAsUpIndicatore(R.drawable.ic_clear_white)
}

with()

with() 함수는 인자로 받는 객체를 이어지는 블록의 리시버로 전달하며, 블록의 결과값을 반환한다.

fun <T,R> with(receiver: T, block: T.() -> R): R

with() 함수는 사실상 run() 함수와 기능이 거의 동일하며, 리시버로 전달할 객체가 어디에 위치하는지만 다르다.

run() 함수는 with() 함수를 좀 더 편리하게 사용하기 위해 let() 함수와 with() 함수를 합쳐놓은 형태라고 봐도 무방하다. 즉, run() 함수는 다음과 같이 표현할 수 있다.

supportActionBar?.let{
	with(it){
		setDisplayHomeAsUpEnabled(true)
		setHomeAsUpIndicator(R.drawable.ic_clear_white)
	}
}

이와 같이 기능은 똑같지만 run() 함수가 안전한 호출을 지원하는데 반해, with() 함수는 이를 자체적으로 지원하지 않으므로 특별한 경우가 아니라면 run() 함수를 더 자주 사용하게 될 것 같다.