Kotlin Examples > Productivity Boosters

HH·2022년 4월 4일
0

Kotlin Examples

목록 보기
7/8

2022-03-16 작성완료

Named Arguments


대부분의 다른 프로그래밍 언어들과 같이(java, c++ 등), 코틀린은 정의된 순서에 따라 메서드와 생성자에 아규먼트를 전달할 수 있다. 코틀린은 또한 더 명확한 호출을 허용하고 아규먼트 순서에 따른 실수를 피할 수 있도록 named arguments를 지원한다. 그러한(아규먼트 순서로 인한) 실수는 컴파일러에 의해 탐지되지 않으므로 발견하기 힘들다. 예를 들어 두 연속된 아규먼트가 같은 타입일 때 그렇다.

fun format(userName: String, domain: String) = "$userName@$domain"

fun main() {
    println(format("mario", "example.com"))                         // 1
    println(format("domain.com", "username"))                       // 2
    println(format(userName = "foo", domain = "bar.com"))           // 3
    println(format(domain = "frog.com", userName = "pepe"))         // 4
}
  1. 아규먼트 값으로 함수를 호출한다.
  2. 순서가 바뀐 아규먼트로 함수를 호출한다. syntax 에러는 없지만, 결과 domain.com@username 은 부정확하다.
  3. 함수를 지명 인자(named arguments)로 호출한다.
  4. 지명 인자(named arguments)를 사용해 호출할 경우 원하는 어떤 순서로든 아규먼트들을 지정할 수 있다.

String Templates


String templates는 변수 참조 및 표현식을 문자열에 포함시킬 수 있도록 한다. 스트링의 값이 요구될 때 (예: println) 모든 참조와 표현식들은 실제 값으로 대체된다.

val greeting = "Kotliner"

println("Hello $greeting")                  // 1 
println("Hello ${greeting.toUpperCase()}")  // 2
  1. 변수 참조를 가진 문자열을 프린트한다. 문자열에서 참조는 $로 시작한다.
  2. 표현식을 가진 문자열을 프린트한다. 문자열은 $로 시작하고 중괄호로 에워싸인다.

Destructuring Declarations


Destructuring declaration 구문은 매우 편리할 수 있다. 특히 멤버에 접근하기 위한 인스턴스가 필요할 때 편리하다. 이것은 지정된 이름 없이 인스턴스를 정의할 수 있게 해 주며, 그로 인해 코드 몇 줄을 줄일 수 있다.

val (x, y, z) = arrayOf(5, 10, 15)                              // 1

val map = mapOf("Alice" to 21, "Bob" to 25)
for ((name, age) in map) {                                      // 2
    println("$name is $age years old")          
}

val (min, max) = findMinMax(listOf(100, 90, 50, 98, 76, 83))    // 3
  1. Array 구조 분해. 왼편 변수의 수는 오른편 아규먼트의 수와 같아야 한다.
  2. 맵 또한 구조 분해 될 수 있다. nameage 변수는 맵의 키와 값에 매핑되었다.
  3. 빌트인 PairTriples 타입도 구조 분해를 지원한다. 심지어 함수의 리턴값일 경우에도 구조 분해 가능하다.
data class User(val username: String, val email: String)    // 1

fun getUser() = User("Mary", "mary@somewhere.com")

fun main() {
    val user = getUser()
    val (username, email) = user                            // 2
    println(username == user.component1())                  // 3

    val (_, emailAddress) = getUser()                       // 4
    
}
  1. 데이터 클래스를 정의한다.
  2. 인스턴스를 구조분해한다. 선언된 값은 인스턴스 필드로 매핑된다.
  3. 데이터 클래스는 자동으로 component1()component2()메서드를 정의한다. 이 메서드들은 구조분해 중에 호출될 것이다.
  4. 사용하지 않을 값이 있다면 언더스코어(_)를 사용한다. 이것은 사용하지 않는 변수를 나타내는 컴파일러 힌트를 피하게 한다.
class Pair<K, V>(val first: K, val second: V) {  // 1
    operator fun component1(): K {              
        return first
    }

    operator fun component2(): V {              
        return second
    }
}

fun main() {
    val (num, name) = Pair(1, "one")             // 2

    println("num = $num, name = $name")
}
  1. component1()component2() 메서드를 가진 커스텀 Pair 클래스를 정의한다.
  2. 이 클래스의 인스턴스를 빌트인 Pair와 동일한 방법으로 구조분해한다.

Smart Casts


코틀린 컴파일러는 대부분의 경우 타입 캐스트를 자동으로 수행할 수 있을 정도로 똑똑하다. 타입 캐스트가 가능한 경우는 다음을 포함한다:

  1. nullable 타입에서 대응하는 non-nullable 타입으로의 캐스트
  2. supertype에서 subtype으로의 캐스트.
import java.time.LocalDate
import java.time.chrono.ChronoLocalDate

fun main() {
    val date: ChronoLocalDate? = LocalDate.now()    // 1

    if (date != null) {
        println(date.isLeapYear)                    // 2
    }

    if (date != null && date.isLeapYear) {          // 3
        println("It's a leap year!")
    }

    if (date == null || !date.isLeapYear) {         // 4
        println("There's no Feb 29 this year...")
    }

    if (date is LocalDate) {
        val month = date.monthValue                 // 5
        println(month)
    }
}
  1. nullable 변수를 선언한다.
  2. non-nullable로 스마트캐스팅해서 isLeapYear에 직접 접근할 수 있게 한다.
  3. 조건 내부에서 스마트캐스팅이 일어난다 (자바와 마찬가지로 코틀린이 단축평가(short-circuiting)을 사용하고 있기 때문에 가능하다). (data !=null을 먼저 계산했기 때문에 가능하다는 뜻으로 추측)
  4. 조건 내부에서 스마트캐스팅이 일어난다 (마찬가지로 단축평가 덕에 가능하다).
  5. 하위 타입 LocalDate로 스마트캐스트된다.

이 방법으로, 분명한 캐스팅을 수동으로 하지 않고도 대부분의 경우 원하는 변수를 자동으로 사용할 수 있다.

0개의 댓글