Kotlin Pair, Triple 그리고 Scope 함수 정리

패스트 캠퍼스 실무 프로젝트로 배우는 Kotlin & Spring 강의 정리

Pair & Triple

  • 코틀린 표준 라이브러리에서 제공하는 데이터 클래스
  • 각각 두 값, 세 값을 저장 가능
  • toString(), toList() 제공

  • first, second, third(triple)은 불변 속성
  • componentN 메서드 가짐

  • 배열이나 리스트에서도 구조 분해 할당 사용 가능하며 내부에서는 componentN 메서드 이용
  • 구조 분해 할당은 각 프로퍼티의 위치에 따라 결정됨
fun main() {
  val pair = Pair("A", 1)
  println(pair.second + 2) // 3
  
  // pair.first = "B" 불변이므로 컴파일 오류 발생
  val newPair = pair.copy(first = "B")	 // copy 메서드 이용해서 새 인스턴스 생성
  
  val pair2 = "One" to 1	// 중위 연산자로 생성 가능
  val map = mutableMapOf(Pair("Two", 2))	// map 생성할 때 Pair 사용 가능
  
  val triple = Triple("a", "b", "c")
  val (a, b, c) = triple	// 구조 분해 할당
  
  val triple2 = Triple("Tom", 25, "UK")
  val (name: String, age: Int, country: String) = triple2
}

Scope Functions

  • 코틀린 표준 라이브러리에서 객체의 컨텍스트 안에서 코드 블록을 실행하기 위해서만 존재하는 함수
  • 스코프 함수를 잘 사용하면 불필요한 변수 선언없이 더 간결하고 읽기 쉬운 코드 작성 가능
  • 스코프 함수의 코드 블록 내부에서는 수신자 객체에 접근 가능
    • 변수명을 사용하지 않고도 객체 접근 가능
  • 수신자 객체는 람다식 내부에서 사용할 수 있는 객체의 참조
  • 스코프 함수를 사용하면 수신자 객체에 대한 참조로 this 또는 it 사용
  • this 는 키워드로서 변수 이름으로 사용 불가
  • it은 소프트 키워드로 변수 이름으로 사용 가능
함수명 수신자 객체 참조 방법 반환 값 확장 함수 여부
let it 함수의 결과 O
run this (생략 가능) 함수의 결과 O
with this (생략 가능) 함수의 결과 X
apply this (생략 가능) 컨텍스트 객체 O
also it 컨텍스트 객체 O
  • let
    • null이 아닌 경우, 사용될 로직을 작성한 후 새로운 결과를 반환할 때 사용
    • let 함수 구문의 가장 마지막이 반환값이 됨
    • let 함수 내부에 중첩 let 함수 구문 가능
    • 중첩 함수가 많아지면 가독성이 떨어지므로 if-else 구문이 더 나을 수 있음
fun main{
  val str1: String? = null
  str1?.let { println(it) }	// 안전연산자와 함께 사용하여 let 함수가 실행되지 않음
  
  val str2: String? = "Hi"
  str2?.let { println(it) }	// Hi
  
  val result = str2?.let {
    println(it)
    1		
  }  
  println(result)	// 1
  
  str2.let {
    val abc: String = "abc"
    abc.let {
      val def: String = "def"
      def.let { println("not null") }
    }
  }	// not null
}
  • run
    • 수신 객체 프로퍼티를 구성하거나 새로운 결과를 반환할 때 사용
    • 함수 내부의 마지막이 반환 값
class DbClient {
    var url: String? = null
    var username: String? = null
    var password: String? = null

    fun connect(): Boolean {
        println("Connected")
        return true
    }
}

fun main() {
    // val config = DbClient()
    // config.url = "localhost:3306"
    // config.username = "mysql"
    // config.password = "1234"
    // val connected = config.connect()

    // run 사용해서 위의 코드 구현
    val connected = DbClient().run {
        url = "localhost:3306"
        username = "mysql"
        password = "1234"
        connect()
    }
    println(connected)	// true
}
  • with
    • 결과 반환없이 내부에서 수신 객체를 이용해서 다른 함수를 호출할 때 사용
    • 다른 함수와 다르게 확장 함수가 아님
    • with 함수에 변수에 대한 참조를 넣음
fun main() {
    val str = "Hi"

    with(str) {
        println("length = $length")
    }

    val length = with(str) { length }
}
  • apply
    • 수신 객체 프로퍼티를 구성하고 수신 객체의 결과를 그대로 반환하고 싶을 때 사용
class DbClient {
    var url: String? = null
    var username: String? = null
    var password: String? = null

    fun connect(): Boolean {
        println("Connected")
        return true
    }
}

fun main() {
    val client: DbClient = DbClient().apply {
        url = "localhost:3306"
        username = "mysql"
        password = "1234"        
    }

    println("client = $client") 	// client = DbClient@279f2327
  	client.connected.run { println(this) }	// connect 메서드 반환값인 true
}
  • also
    • 부수 작업을 수행하거나 전달받은 수신 객체를 그대로 결과로 반환하고 싶을 때 사용
class User(val name: String, val password: String) {

    fun validate() {
        if (name.isNotEmpty() && password.isNotEmpty()) {
            println("Validated")
        } else {
            println("Not Validated")
        }
    }
}

fun main() {
    User("Tom", "1234").also { 
        it.validate()		// "Validated"
      	it.printName()	// Tom
    }
}