ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • kotlin) 추가적으로 알아두어야 할 코틀린 특성
    kotlin 2024. 7. 13. 17:04

    코틀린의 이모 저모

    1. Type Alias 와 as import

    개념 : 긴 이름의 클래스 혹은 함수 타입이 있을때 축약하거나 더 좋은 이름을 쓰고 싶을때 사용

     

    Type Alias

    //기존 함수
    fun filterFruits(fruits: List<Fruit>, filter: (Fruit) -> Boolean): List<Fruit> {
    }
    //typealias 를 통해 미리 type 을 정해서 적용
    typealias FruitFilter = (Fruit) -> Boolean
    fun filterFruits(fruits: List<Fruit>, filter: FruitFilter): List<Fruit> {
    
    }
    
    data class UltraUperGuardianTribe(
        val name : String
    )
    //이름이 긴 클래스를 컬렉션에 사용할 때도 간단하게 줄일 수 있다.
    typealias USGTMap = Map<String, UltraUperGuardianTribe>

    as import

    //사용하려는 패키지의 이름을 변경할 수 있다.
    import com.lannstart.lec19.a.printHellowWorld as printHelloWorldA
    import com.lannstart.lec19.b.printHellowWorld as printHelloWorldB

    2. 구조분해와 componentN 함수

    구조분해

    data class Person(
        val name: String,
        val age: Int
    )
    
    fun main() {
        var person = Person("JS",100)
        val (name, age) = person                //name, age 변수를 생성
    //    val name = person.component1()        //name 를 각각 component 를 통해 가져옮
    //    val age = person.component2()         //age  순서를 반드시 지켜야함
        println("이름 : $name, 나이 : $age")
    }

    componentN

    class Person(
        private val name: String,
        private val age: Int
    ){
        //연산자 이기 때문에 operator 함수를 사용해야함
        operator fun component1(): String {
            return this.name
        }
    
        operator fun component2(): Int {
            return this.age
        }
    }
    
    fun main() {
        var person = Person("JS",100)
        val (name, age) = person
        println("이름 : $name, 나이 : $age")
        
        val map = mapOf(1 to "A", 2 to "B")
        for((key, value) in map.entries) {  //(key,value) 역시 구조분해 문법
        }
    }

    3. Jump 와 Label

    • return : 기본적으로 가장 가까운 encloseing function 또는 익명 함수로 값이 반환된다.
    • break : 가장 가까운 루프가 제거된다.
      • foreach 에서는 사용할 수 없다.
      • 사용하고 싶다면 run 으로 감싼 함수에서 return@run 을 사용 
    • continue : 가장 가까운 루프를 다음 step 으로 보낸다.
      • foreach 에서는 사용할 수 없다.
      • 사용하고 싶다면 run 으로 감싼 함수에서 return@forEach 을 사용

    Jump

    fun main() {
        val numbers = listOf(1,2,3)
        numbers.map { number -> number + 1}
            .forEach { number -> println(number) }
    
        for( number in numbers){
            if (number == 2) {
                continue        //사용 가능
                break           //사용 가능
            }
        }
    
        numbers.forEach { number ->
            if (number == 2){
                continue        //사용 불가능
                break           //사용 불가능
            }
        }
        
        run{                        //run 으로 한번 감싸야한다.
            numbers.forEach { number ->
                if (number == 2){
                    return@run      //break 와 동일
                    return@forEach  //continue 와 동일
                }
            }
        }
    }

    차라리 foreach 보다 for 문을 최대한 사용하는것을 추천

     

    Label

    fun main() {
        abc@ for(i in 1..100){          //"abc" 라벨을 생성하고 
            for(j in 1..100){
                if(j == 2){
                    break@abc                  //"abc" 라벨 위치의 for 문을 종료 함
                }
                println("${i} ${j}")
            }
        }
    }

    4. TakeIf 와 TakeUnless

    fun getNumberOrNull(): Int? {
        return if(number <= 0){
            null
        } else {
            number
        }
    }
    
    fun getStringOrNull2(): Int? {
        return number.takeIf{it > 0}        //주어진 조건을 만족하면 그 값이, 그렇지 않으면 null 이 반환
    }
    
    fun getStringOrNull3(): Int? {
        return number.takeUnless{it <= 0}    //주어진 조건을 만족하지 않으면 그 값이, 그렇지 않으면 null 이 반환
    }

    코틀린의 scope function

    1. scope function 이란 무엇인가?

    • scope : 영역
    • function : 함수
    • scope function : 일시적인 영역을 형성하는 함수
    • 람다를 사용해 일시적인 영역을 만들고
    • 코드를 더 간결하게 만들거나, method chaning 에 활용하는 함수를 scope function 이라고 합니다.

    let

    public inline fun <T,R> T.let(block: (T) -> R): R {     //let : 확장함수. 람다를 받아, 람다 결과를 반환
        return block(this)
    }
    fun printPerson(person: Person?){
    //    if(person != null){
    //        println(person.name)
    //        println(person.age)
    //    }
        //위 코드를 아래 코드로 변경
        person?.let{            //Safe.Call (?.) 을 사용 : person 이 null 이 아닐때 let 을 호출
            println(it.name)    //람다 {} 를 사용하며 람다 안에서 it 을 통해 person 에 접근
            println(it.age)
        }
    }

    2. scope function 의 분류

    • let, run : 람다의 결과 
    • also, apply : 객체 그 자체
    • with : this를 사용해 접근하고, this는 생략 가능하다.
    val value1 = person.let{
        it.age                  //let : 람다의 결과가 최종적으로 반영
    }
    
    val value2 = person.run{
        this.age                //run : 람다의 결과가 최종적으로 반영
    }
    
    val value3 = person.also{
        it.age                  //also : 결과와는 무관하게 객체 그 자체, person 그 자체가 최종적으로 리턴
    }
    
    val value4 = person.apply{
        this.age                //apply : 결과와는 무관하게 객체 그 자체, person 그 자체가 최종적으로 리턴
    }
    • this : 생략이 가능한 대신, 다른 이름을 붙일 수 없다.
      • 파라미터 자체에서 일반 함수를 받는다. 그렇기에 일반 함수는 파라미터를 받아서 파라미터를 함수 내부에서 호출
    • it : 생략이 불가능한 대신, 다른 이름을 붙일 수 있다.
      • 확장함수를 받는다. 확장함수는 본인 자신을 this로 호출하고, 생략할 수 있다.
    val value1 = person.let { p -> 	//person 의 다른이름 "p" 를 사용할 수 있다.
        p.age
    }
    
    val value2 = person.run {		//person 의 이름 그대로 혹은 묵음,this 로 사용해야 한다.
        age
    }

    3. 언제 어떤 scope function 을 사용해야 할까?

    1. 하나 이상의 함수를 call chain 결과로 호출할 때
    2. non-null 값에 대해서만 code block 을 실행시킬 때
    3. 일회성으로 제한된 영역에 지역 변수를 만들 때

    4. scope function 과 가독성

    scope function 을 사용한 코드가 그렇지 않은 코드보다 가독성이 좋은 코드일까?

    // 1번 코드
    if (person != null && person.isAdult){
        view.showPerson(person)
    } else {
        view.showError()
    }
    
    // 2번 코드
    person?.takeIf { it.isAult }
        ?.let(view::showPerson)
        ?: view.showError()
    1. 구현 2는 숙련된 코틀린 개발자만 더 알아보기 쉽다. 어쩌면 숙련된 코틀린 개발자도 잘 이해하지 못할 수 있다.
    2. 구현 1의 디버깅이 쉽다.
    3. 구현이 1이 수정도 더 쉽다.

    사용 빈도가 적은 관용구는 코드를 더 복잡하게 만들고 이런 관용구들을 한 문장 내에서 조합해 사용하면 복잡성이 훨씬 증가한다.

     

     

    댓글

Designed by Tistory.