ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 20강. 코틀린의 scope function
    BackEnd/Kotlin 2024. 5. 23. 22:00
    반응형
    1. scope function이란 무엇인가?!
    2. scope function의 분류
    3. scope function과 가독성

     

    scope function이란 무엇인가?!

    • scope: 영역
    • function: 함수
    • scope function: 일시적인 영역을 형성하는 함수

     

      람다를 사용해 일시적인 영역을 만들고 코드를 더 간결하게 만들거나, method chaning에 활용하는 함수를 scope function이라고 합니다. 다음은 scope function의 한 종류인 let을 사용하여 refactoring 한 코드입니다.

    fun printPerson(person: Person?) {
        if (person != null) {
            println(person.name)
            println(person.age)
        }
    }
    fun printPerson(person: Person?) {
        person?.let {
            println(it.name)
            println(it.age)
        }
    }
    • Safe Call (?.)을 사용하여 person이 null이 아닐 때 let을 호출합니다.

     

    scope function의 분류

      it 사용 this 사용
    람다의 결과를 반환하는 확장함수 let run
    객체 그 자체를 반환하는 확장함수 also apply
    확장함수 X   with(파라미터, 람다)
    • this: 생략이 가능한 대신, 다른 이름을 붙일 수 없습니다.
    • it: 생략이 불가능한 대신, 다른 이름을 붙일 수 있습니다.

     

    let

    • 하나 이상의 함수를 call chain 결과로 호출 할 때 사용합니다.
        val strings = listOf("APPLE", "CAR")
        strings.map { it.length }
            .filter { it > 3 }
            .let(::println)
    • non-null 값에 대해서만 code block을 실행시킬 때 사용합니다.
        val length = str.let {
            println(it.uppercase())
            it.length
        }
    • 일회성으로 제한된 영역에 지역 변수를 만들 때 사용합니다.
        val numbers = listOf("one", "two", "three", "four")
        val modifiedFirstItem = numbers.first()
            .let { firstItem ->
                if (firstItem.length >= 5) firstItem else "!$firstItem!"
            }.uppercase()
        println(modifiedFirstItem)

     

    run

    • 객체 초기화와 반환 값의 계산을 동시에 해야할 때 사용합니다.

      다음은 객체를 만들어 DB에 저장하고, 바로 그 인스턴스를 활용하는 코드입니다.

        val person = Person("Kotlin", 100).run(personRepository::save)
    
        // or
        
        val person = Person("Kotlin", 100).run { 
            hobby = "독서"
            personRepository.save(this)
        }

     

    apply

    • 객체 설정을 할 때 객체를 수정하는 로직이 call chain 중간에 필요할 때 사용합니다.

      다음은 최초 Person 클래스를 생성할 때는 name과 age만 받다가 회원가입 이후에 hobby를 추가적으로 설정해주는 코드입니다.

    fun createPerson(
        name: String,
        age: Int,
        hobby: String,
    ): Person {
        return Person(
            name = name,
            age = age,
        ).apply {
            this.hobby = hobby
        }
    }

     

    also

    • 객체를 수정하는 로직이 call chain 중간에 필요할 때 사용합니다.
        mutableListOf("one", "two", "three")
            .also { println("four 추가 이전 지금 값: $it") }
            .add("four")

     

    with

    • 특정 객체를 다른 객체로 변환해야 하는데, 모듈 간의 의존성에 의해 정적 팩토리 혹은 toClass 함수를 만들기 어려울 때 사용합니다.
        return with(person) {
            PersonDto(
                name = name,
                age = age,
            )
        }

     

    scope function과 가독성

        // 1번 코드: 전통적인 if else를 활용한 코드
        if (person != null && person.isAdult) {
            view.showPerson(person)
        } else {
            view.showError()
        }
    
        // 2번 코드: scope function을 활용한 코드
        person.takeIf { it.isAdult }
            ?.let(view::showPerson) 
            ?: view.showError()
    • 2번 코드는 숙련된 코틀린 개발자가 아니면 잘 이해하지 못할 수 있습니다.
    • 1번 코드가 디버깅이 더 쉬우며, 수정 또한 쉽습니다.

     

    사용 빈도가 적은 관용구는 코드를 더 복잡하게 만들고,

    이런 관용구들을 한 문장 내에서 조합해 사용하면 복잡성이 훨씬 증가할 수 있습니다.

     

     

     

    감사합니다.

    반응형

    댓글

Designed by Tistory.