분리 선언
때로는 객체를 여러 변수로 분리하는 것이 편
val (name, age) = person
이 구문을 분리 선언(destructuring declaration)이라고 한다.
println(name)
println(age)
이 분리 선언은 다음 코드로 컴파일된다
val name = person.component1()
val age = person.component2()
component1()
과 component2()
함수는 Kotlin에서 널리 사용되는 규칙의 예이다 (+, *, for-loops 연산자 참조). 분리 선언의 오른쪽에 있는 것은 필요한 수의 component 함수를 가지고 있으면 된다.
분리 선언에서 componentN()
함수를 사용하려면 operator
키워드를 표시해야한다
분리 선언은 for-loops 에서도 동작한다
for ((a, b) in collection) { ... }
변수 a, b에 component1(), component2()의 반환값을 갖는다
Example: 함수에서 2개의 값을 반환
간단한 방법은 데이터 클래스를 선언하고 인스턴스를 반환하는 것이다
data class Result(val result: Int, val status: Status)
fun function(...): Result {
// 계산
return Result(result, status)
}
// 이제, 이 암수를 사용:
val (result, status) = function(...)
데이터 클래스는 componentN()
함수를 자동으로 선언하기 때문에 여기서 선언을 분리해야한다
NOTE: 표준 클래스
Pair
를 사용하고function()
이Pair<Int, Status>
를 반환하도록 할 수 있지만, 데이터 이름을 올바르게 지정하는 것이 좋다
Example: 분리 선언과 맵
맵을 탐색하는 좋은 방법은 다음과 같다
for ((key, value) in map) {
// 키와 값으로 무엇가한다
}
이 작업을 위해서 아래 조건이 충족되어야 한다
iterator()
함수를 제공- 각 요소를
component1()
과component2()
함수를 젲공하는 페어로 제공해야한다.
실제로 표준 라이브러리는 다음과 같은 확장을 제공한다.
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator()
operator fun <K, V> Map.Entry<K, V>.component1() = getKey()
operator fun <K, V> Map.Entry<K, V>.component2() = getValue()
따라서 맵 (물론 데이터 클래스의 인스턴스 콜렉션)을 사용하는 for-loops 에서 자유롭게 분리 선언을 사용할 수 있다
미사용 변수는 밑줄 (1.1 이후)
분리 선언에 변수가 필요하지 않으면 밑줄을 사용할 수 있다
val (_, status) = getResult()
람다에서 분리 (1.1 이후)
람다 파라미터에 대해 분리 선언 구문을 사용할 수 있다. 람다가 Pair
타입 (Map.Entry
또는 적절한 componentN
함수를 가지는 다른 타입)의 파라미터를 가지고 있다면 괄호안에 넣음으로 하나가 아닌 여러개의 새로운 파라미터를 도입할 수 있다
map.mapValues { entry -> "${entry.value}!" }
map.mapValues { (key, value) -> "$value!" }
두 개의 파라미터를 선언하고 파라미터 대신 분리 페어를 선언하는 것의 차이점에 유의하자
{ a -> ... } // 하나의 파라미터
{ a, b -> ... } // 두 개의 파라미터
{ (a, b) -> ... } // 분리된 Pair
{ (a, b), c -> ... } // 분리된 Pair와 다른 파라미터
분리된 파라미터가 사용되지 않는 경우 밑줄로 대체하여 이름을 만들지 않도록 할 수 있다
map.mapValues { (_, value) -> "$value!" }
전체 분리된 파라미터 또는 특정 요소의 유형을 별도로 지정 가능
map.mapValues { (_, value): Map.Entry<Int, String> -> "$value!" }
map.mapValues { (_, value: String) -> "$value!" }