Apple is Apple

일일 회고

 

프로그래밍에 도움을 주는 kotlin의 유용한 기능에 대해 공부하였다.

 

Scope function,  Stream 열지 않고 사용 할 수 있는 다양한 변환 함수들, 확장 함수 등..

 

이런 편리한 기능들 덕분에 Java보다 Kotlin이 편하고 생산성이 향상된다고 하는 것 같다.

(나도 이런 것들이 Kotlin의 매력이라 생각한다.  최애는 null safety인건 비밀)

 

물론 오늘 공부한 것 이외에도 굉장히 다양한 기능들이 있지만 한 번에 공부한다는 것은 불가능하기에....

많이 접해보면서 익혀보면 될 것 같다!

 


오늘의 주요 Keyword

  • Kotlin Scope function
  • Kotlin의 다양한 기능

 


Kotlin의 유용한 기능

형변환

Kotlin은 자료형마다 형변환 메소드를 제공한다.

 

일반자료형 (Int, Double, String.. 등) 은 toXXX()메소드로 쉽게 형변환이 가능하다.

객체자료형 같은 경우 Type Casting (Up Casting, Down Casting) 을 통해 형변환을 한다

 

물론 모든 타입 -> 모든 타입으로 형변환이 되는 것은 아니니 잘 살펴야한다.

 

타입 확인

is 키워드를 통해 자료형의 타입을 확인해 볼 수 있다.

 

Pair & Triple

각각 2개, 3개의 객체를 저장할 수 있는 특수한 객체이다.

기존에는 여러 타입의 객체를 한 번에 리턴하려면 Data Class를 설계해야 하는데 Pair와 Triple은 이런 번거로움을 줄여준다.

// 선언
val pair = Pair("123", 123)
val triple = Triple("123", 123, 123.123)
// 접근
pair.first // "123"
pair.second // 123
triple.first // "123"
triple.second // 123
triple.third // 123.123

 

Scope function

Kotlin에서 제공하는 Scope function이다.

주로 객체와 함께 사용되며 편리하고 간결한 코드 작성을 도와준다.

간결한 코드 작성을 위해 필수적으로 알아두면 좋은 챕터라고 생각한다.

 

이름에서 알 수 있듯이 이 함수를 호출하면 Scope가 생기게 되고 이 Scope안에서는 전달된 객체가

"it" 또는 "this"라는 이름의 Context Object로 사용할 수 있게 된다.

 

Scope function 총 5가지가 있는데 함수마다 Context Object(전달된 객체)를 참조하는 방법과 리턴 값(Context Object or lambda)이 상이하다.

 

1. let

let은 null이 아닌 값만 실행시키고 싶을 때 주로 사용된다. 그래서 let은?. 연산자와 같이 사용되는 경우가 많다.

Scope에는 it으로 전달하고 수행된 결과(lambda)를 반환한다. 

val student = Student?.let {
    it.name = "James"
    it.grade = 3
    it.grade // 반환 값
}

 

2. with

with는 Scope에 this로 전달하여 내부 로직을 실행하고 실행된 결과(lambda)를 반환한다.

null이 아닌 객체를 사용하므로 반드시 null이 아닐 때만 사용한다.

val student = Student("길동", 3)
with(student) {
    println(name) // this.name
    println(grade) // this.grade
}

 

3. also

also는 Scope에 it으로 전달하여 로직을 실행하고 Context Object(객체 자체)를 반환한다.

객체의 유효성을 확인하거나 디버깅등 부가적인 목적으로 주로 사용한다.

val numbers = mutableListOf("one", "two", "three")
numbers.also { println("새 항목 추가하기 전 리스트 요소들: $it") }
       .add("four")

 

4. apply

apply는 Scope에 this로 전달하여 로직을 실행하고 ContextObject(객체 자체)를 반환한다.

주로 객체의 상태를 바꾸거나 초기화할 때 사용한다.

val student = Student("길동", 3)
var result = student?.apply {
    name = "지수"
}

5. run

run은 두 가지 형태가 있다.

 

1. 객체에서 호출할 때

with처럼 객체를 받아 로직을 실행한 후(Scope에서 this로 사용) 실행된 결과(lambda)를 반환한다.

어떤 값을 계산할 필요가 있거나, 여러 개의 지역변수 범위를 제한할 때 사용한다.

그리고 with와 달리 null 체크를 수행할 수 있어 안전하게 사용가능하다.

val student = Student("길동", 3)
var result = student?.run {
    goToClassroom()
}

 

2. 객체에서 호출하지 않을 때

 - 이 때는 확장함수가 아니고, Scope에 객체를 전달받아서 속성을 바꾸는 그런 형식이 아니다.

 - 단지 객체 생성이나 기타 명령문을 블록 안에 묶는 역할을 한다.

var totalGrade = run {
    var korean = 100
    var math = 80

    korean + math
}
println(totalGrade)

함수의 Scope 내 수신 객체와 return을 표로 정리하면 다음과 같다.

Scope function 수신 객체 return
let it lambda result
with this lambda result
also it context object
apply this context object
run this lambda result
run - lambda result

 

+ 주의, Scope function을 사용할 때 중첩해서 사용하는 경우가 있는데, 이때, 수신객체를 모두 it으로 하면 문제가 발생할 수 있다.

listOf(listOf(1,2,3), listOf(4,5,6), listOf(7,8,9)).forEach { outer -> 
    println(it) // name-shadowed   --> X
    println(outer) --> O
    outer.forEach{ inner ->
        println(it) // name-shadowed --> X
        println(inner) --> O
    }
}
// it이 중복되어 어떤 it인지 제대로 참조 못할 수 도 있다
// it의 alias를 지정하여 Name-shadowed를 방지한다
profile

Apple is Apple

@mjjjjjj