728x90
반응형
✅ 수신 객체 지정 람다 : with와 apply
- 코틀린에서 정의하고 있는 with와 apply 함수는 매우 편리하며 많은 사람들이 이용 중이며 이러한 코틀린 만의 람다식에는 독특한 특징이 있다.
- 그 기능은 바로 수신 객체를 명시하지 않고 람다의 본문 안에서 다른 객체의 메소드를 호출할 수 있게 하는 것이다.
- 이러한 람다를 수신 객체 지정 람다라고 부른다.
- 수신 객체 지정 람다는 Scope Function이라고도 하며 with와 apply 외의 다른 함수에 대해 알고 싶은 경우 아래 글을 참고하기를 바란다.
[Kotlin] 코틀린의 Scope Function(범위 지정 함수)
✅ 코틀린의 Scope Function이란? 코틀린 표준 라이브러리에서 제공하는 확장함수 목적 : 간결성, 명료성, 유지보수 용이성 정의 : 객체의 컨텍스트 내에서, 실행 가능한 코드 블럭을 만드는 함수 종
dahoonkk.tistory.com
📌 with 함수
- 어떤 객체의 이름을 반복하지 않고도 그 객체에 대해 다양한 연산을 수행할 수 있다면 편리할 것이다.
- 다양한 이러한 기능을 제공하며 코틀린도 마찬가지 기능을 제공한다.
- 하지만 언어 구성 요소로 제공하지 않고 with라는 라이브러리 함수를 통해 제공한다.
- 다양한 이러한 기능을 제공하며 코틀린도 마찬가지 기능을 제공한다.
- 아래 예제를 살펴보고 이를 with 함수로 리팩토링해보자.
/* 알파벳 만들기 */
fun alphabet(): String {
val result = StringBuilder()
for(letter in 'A'..'Z') {
result.append(letter)
}
result.append("\nNow I know the alphabet!")
return result.toString()
}
println(alphabet())
// ABCDEFGHIJKLMNOPQRSTUVWXYZ
// Now I know the alphabet!
- 이 예제에서 result에 대해 다른 여러 메서드를 호출하면서 매번 result를 반복 사용한다.
- 이러한 반복은 번거로운 작업이 될 수 있다.
- 이를 개선해 with로 다시 작성해보자.
/* with를 사용해 알파벳 만들기 */
fun alphabet(): String {
val stringBuilder = StringBuilder()
return with(stringBuilder) { // 메서드를 호출하려는 수신 객체를 지정한다.
for(letter in 'A'..'Z') {
this.append(letter) // "this"를 명시해서 앞에서 지정한 수신 객체의 메서드를 호출한다.
}
append("\nNow I know the alphabet!") // "this"를 생략하고 메서드를 호출한다.
this.toString() // 람다에서 값을 반환한다.
}
}
- with 함수는 첫 번째 인자로 받은 객체를 두 번째 인자로 받은 람다의 수신 객체로 만든다.
- 인자로 받은 람다 본문에서는 this를 사용해 그 수신 객체에 접근할 수 있다.
- 일반적인 this와 마찬가지로 this와 점(.)을 사용하지 않고 프로퍼티나 메서드 이름만 사용해도 수신 객체의 멤버에 접근할 수 있다.
- with가 반환하는 값은 람다 코드를 실행한 겨로가이며, 그 결과는 람다 식의 본문에 있는 마지막 식의 값이다.
- 하지만 때로는 람다의 결과 대신 수신 객체가 필요한 경우도 있다.
- 이러한 경우 apply 라이브러리 함수를 사용할 수 있다.
📌 apply 함수
- apply 함수는 거의 with와 같다.
- 유일한 차이란 apply는 항상 자신에게 전달된 객체(즉 수신 객체)를 반환한다는 점이다.
- apply를 써서 alphabet 함수를 다시 리팩터링해보자.
fun alphabet() = StringBuilder().apply {
for(letter in 'A'..'Z') {
append(letter)
}
append("\nNow I know the alphabet!")
}.toString()
- apply는 확장 함수로 정의돼 있으며, apply의 수신 객체가 전달받은 람다의 수신 객체가 된다.
- 위의 함수에서 apply를 실행한 결과는 StringBuilder 객체로 그 객체의 toString을 호출하여 String 객체를 얻을 수 있다.
- 이런 apply 함수는 객체의 인스턴스를 만들면서 즈깃 프로퍼티 중 일부를 초기화해야 하는 경우에 유용하다.
- 자바에서는 보통 별도의 Builder 객체가 이런 역할을 담당하지만 코틀린에서는 어떤 클래스가 정의돼 있는 라이브러리의 특별한 지원 없이도 그 클래스 인스턴스에 대해 apply를 활용할 수 있다.
- apply를 객체 초기화에 활용하는 예로 안드로이드의 TextView 컴포넌트를 만들면서 특성 중 일부를 설정해보자.
/* apply를 TextView 초기화에 사용하기 */
fun createViewWithCustomAttributes(context: Context) =
TextView(context).apply {
text = "Sample Text"
textSize = 20.0
setPadding(10, 0, 0, 0)
}
- 이처럼 apply 함수를 사용하면 함수의 본문에 간결한 식을 사용할 수 있다.
- 새로운 TextView 인스턴스를 만들고 즉시 그 인스턴스를 apply에 넘긴다.
- apply에 전달된 람다 안에서는 TextView가 수신 객체가 된다.
- 따라서 원하는 대로 TextView의 메서드를 호출하거나 프로퍼티를 설정할 수 있다.
- 람다를 실행하고 나면 apply는 람다에 의해 초기화된 TextView 인스턴스를 반환한다.
❗️ 그 외 : buildString
- with와 apply는 수신 객체 지정 람다를 사용하는 일반적인 예제 중 하나이다.
- 더 구체적인 함수를 비슷한 패턴으로 활용할 수 있다.
- 예를 들어 표준 라이브러리의 buildString 함수를 사용하면 alphabet 함수를 더 단순화할 수 있다.
- alphabet 코드에서 StringBuilder 객체를 만드는 일과 toStirng을 호출해주는 일을 알아서 해준다.
- buildString의 인자는 수신 객체 지정 람다며, 수신 객체는 항상 StringBuilder가 된다.
- 예를 들어 표준 라이브러리의 buildString 함수를 사용하면 alphabet 함수를 더 단순화할 수 있다.
/* buildString으로 알파벳 만들기 */
fun alphabet() = buildString {
for (letter in 'A'..'Z') {
append(letter)
}
append("\nNow I know the alphabet!")
}
728x90
반응형
'Studying > Kotlin' 카테고리의 다른 글
[Kotlin In Action] 6장. 코틀린 타입 시스템(2) - 널 가능성[2] (0) | 2023.05.30 |
---|---|
[Kotlin In Aciton] 6장. 코틀린 타입 시스템(1) - 널 가능성[1] (0) | 2023.05.25 |
[Kotlin In Action] 5장. 람다로 프로그래밍(4) - 자바 함수형 인터페이스 활용 (0) | 2023.05.23 |
[Kotlin In Action] 5장. 람다로 프로그래밍(3) - 지연 계산(lazy) 컬렉션 연산 (0) | 2023.05.22 |
[Kotlin In Action] 5장. 람다로 프로그래밍(2) - 컬렉션 함수형 API (0) | 2023.05.18 |