- scope function이란?
- scope function의 종류
- 언제 어떤 scope function을 사용해야 하나?
- scope function과 가독성
1 . scope function이란?
- 람다를 사용해 일시적인 영역을 만들고, 코드를 더 간결하게 만들거나 method chaning에 활용하는 함수
2 . scope function의 종류
□ 종류
| let | 확장함수 | 람다의 결과를 반환 |
| run | ||
| alse | 람다의 결과와 무관하게 객체 그 자체를 반환 |
|
| apply | ||
| with | 확장함수가 아님 |
fun printPerson(person: Person?) {
val value1 = person.let { // 람다의 결과값인 age가 value1 에 들어간다
it?.age
}
val value2 = person.run { // 람다의 결과값인 age가 value1 에 들어간다
this?.age
}
val value3 = person.also { // 객체인 person이 들어간다
it?.age
}
val value4 = person.apply { // 객체인 person이 들어간다
this?.age
}
with(person) {
print(name)
print(this.age)
}
}
- 확장함수에 집어넣은 람다에서 수신객체를 호출할 때, it을 쓰나 this를 쓰냐 차이가 있다.
| this | 생략 가능, 다른 이름을 붙일 수 없다. |
| it | 생략 불가, 다른 이름을 붙일 수 있다. |
fun printPerson(person: Person) {
val value1 = person.let { p -> // it
p.age
}
val value2 = person.run { // this
age
}
}
□ let, also / run, apply 코드
- block 파라미터는 [T:함수 -> R:반환] 즉, 함수를 실행하여 결과값을 사용한다.
// let의 block(매개값)은 람다를 받아 그 결과값을 반환한다
public inline fun <T, R> T.let(block: (T) -> R): R {return block()}
public inline fun <T> T.also(block: (T) -> Unit): T {
block(this)
return this
}
// run, apply의 block(매개값)은 확장함수를 받아 그 결과값을 반환한다
public inline fun <T, R> T.run(block: T.() -> R): R {return block()}
public inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}
□ with 코드
- with(파리미터, 람다) : this를 사용해 접근
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
return receiver.block()
}
3 . 언제 어떤 scope function을 사용해야 하나?
□ let
① 하나 이상의 함수를 call chain 결과로 호출할 때 사용
② non-null 값에 대해서만 code block을 실행 (자주 사용)
③ 일회성으로 제한된 영역에 지역 변수를 만들 때 (depth 이슈로 권장 x)
fun main() {
// 1
val String = listOf("apple", "ba", "orange")
String.map { it.length }
.filter {it > 3}
.let(::println) // .let { len -> println(len) } 과 같음
// let은 앞의 결과 List<Int>에 대해서 호출
// 2
val str = "apple"
val length = str?.let {
println(it.uppercase())
it.length
}
// 3
val numbers = listOf("one", "two", "three", "four")
val modifiedFirstItem = numbers.first()
.let { firstItem ->
if (firstItem.length >= 5) firstItem else "!${firstItem}"
}.uppercase()
print(modifiedFirstItem)
}
□ run
① 객체 초기화와 반환 값의 계산을 동시에 해야 할 때
- 1. 대체 와 같은 코드로 사용해도 되기 때문에 잘 사용하진 않는다. 반복되는 생성 후 처리(①의 hobby부분)는 생성자, 프로퍼티, init block으로 넣는 것이 좋다.
- 생성자가 너무 길어지는 경우 사용하면 이를 이용해서 코드 가독성이 좋은 걸 선택
// 1. 객체를 만들어 DB에 바로 저장하고 그 인스턴스를 활용
val person1 = Person("홍길동", 20).run(personRepository::save)
val person2 = Person("홍길동", 20).run {
hobby = "독서"
personRepository.save(this)
}
// 1. 대체
val person = personRepository.save(Person("홍길동", 20)
□ apply : 객체 그 자체가 반환 된다.
① 객체 설정을 할 때 객체를 수정하는 로직이 call chain 중간에 필요할 때 사용
- 예로 들어 회원가입 할 때 이름/나이만 입력하고 나중에 정보 수정할 때 취미를 입력하는 경우
- 생성자에는 '취미' 프라퍼티가 들어가지 않는다. (text fixture)
fun createPerson(
name: String,
age: Int,
hobby: String,
): Person {
return Person(
name = name,
age = age,
). apply {
this.hobby = hobby
}
}
□ also : 객체 그 자체가 반환 된다.
① 객체 "수정"하는 로직이 call chain 중간에 필요할 때
var balance: Int = 500
balance.also {println("Balance 입금 이전: $balance")} // 500
.plus(500)
.let{ it -> println("입금 후 $it")} // 1000
□ with : 특정 객체를 다른 객체로 변환해야 하는데, 모듈 간 의존성에 의해 정적 팩토리 혹은 toClass 함수를 만들기 어려울 때 사용 (this 생략으로 간결해짐)
fun createPerson(person: Person) {
return with(person) {
PersonDto(
name = name,
age = age,
)
}
}
4 . scope function과 가독성
- scope function을 활용한 것과 아닌 것을 비교하면
▶ 구현 1이 디버깅이 더 쉽고 수정이 더 쉽다, 자바 개발자 입장에서는 구현 1이 더 가독성이 좋다
- view:: showPerson()이 null을 반환한다면 let이하에서 예기치 않는 버그가 발
// 구현1
fun checkPs(person: Person, view: View) {
if(person != null && person.age > 18) {
view.showPerson(person)
} else {
view.showError()
}
}
// 구현2
fun checkPs(person: Person, view: View) {
person.takeif {it.age > 18}
?.let(view::showPerson)
?: view.showError()
}
▶ 적절한 convention을 적용하면 유용하게 활용할 수 있다.
※ (intellij) 코틀린 코드 자바로 변환
tool > Kotlin > Show Kotlin Bytecode
자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide)| 최태현 - 인프런 강의
현재 평점 5.0점 수강생 3,556명인 강의를 만나보세요. 이 강의를 통해 Kotlin 언어의 특성과 배경, 문법과 동작 원리, 사용 용례, Java와 Kotlin을 함께 사용할 때에 주의할 점 등을 배울 수 있습니다. Ko
www.inflearn.com
'Kotlin > Java to Kotlin Guide' 카테고리의 다른 글
| Type Alias·as import / 구조분해·componentN / Jump·Label / Takeif · TakeUnless (0) | 2025.10.09 |
|---|---|
| FP - 컬렉션을 함수형으로 다루는 방법 (0) | 2025.10.09 |
| FP - 람다 (0) | 2025.10.09 |
| FP - 다양한 함수 (0) | 2025.10.09 |
| FP - 배열과 컬렉션 (0) | 2025.10.08 |