컬렉션을 처리할 때 쓸 수 있는 코틀린 표준 라이브러리 함수 몇 가지를 설명하겠다.
- vararg 키워드를 사용하면 호출 시, 인자 개수가 달라질 수 있는 함수를 정의할 수 있다.
- 중위 함수 호출 구문을 사용하면 인자가 하나뿐인 메소드를 간편하게 호출할 수 있다.
- 구조 분해 선언을 사용하면 복합적인 값을 분해해서 여러 변수에 나눠 담을 수 있다.
자바 컬렉션 API 확장
코틀린 컬렉션은 자바와 같은 라이브러리 클래스를 사용하는 걸로 알고 있을 것이다.
그런데 코틀린 컬렉션은 어찌 더 확장된 API를 사용할수 있을까?
ex) .last(), .maxOrNull()
그 이유는 확장함수이다.
코틀린은 확장함수가 있어 사용할 수 있고, 따라서 자바 라이브러리 클래스의 인스턴스인 컬렉션에 코틀린이 새로운 기능을 추가할 수 있고, 그걸 사용할 수 있어. 더 확장된 API를 쓸 수 있다는 말을 할 수 있다.
// 확장함수
public fun <T> List<T>.last(): T {
if (isEmpty())
throw NoSuchElementException("List is empty.")
return this[lastIndex]
}
// 확장함수
@SinceKotlin("1.4")
public fun <T : Comparable<T>> Iterable<T>.maxOrNull(): T? {
val iterator = iterator()
if (!iterator.hasNext()) return null
var max = iterator.next()
while (iterator.hasNext()) {
val e = iterator.next()
if (max < e) max = e
}
return max
}
가변 인자 함수
리스트를 생성하는 함수를 호출 할 때 원하는 만큼 많이 원소를 전달할 수 있다.
val list = listOf(2, 3, 7, 88, 192)
// 실제 내부 API
public fun <T> listOf(vararg elements: T): List<T> = if (elements.size > 0) elements.asList() else emptyList()
자바의 가변 길이 인자에 익숙할 것이다.
가변 길이 인자는 메소드를 호출할 때 원하는 개수만큼 값을 인자로 넘기면 자바 컴파일러가 배열에 그 값들을 넣어주는 기능이다.
코틀린 가변 길이 인자도 자바와 비슷하다.
다만 문법이 조금 다르다.
자바의 경우 ... 를 붙이는 대신 코틀린에서는 파라미터 앞에 vararg 변경자를 붙인다.
이미 배열에 들어있는 원소를 가변 길이 인자로 넘길 때도 코틀린과 자바 구문이 다르다.
자바에서는 배열을 그냥 넘기면 되지만,
코틀린에서는 배열을 명시적으로 풀어서 배열의 각 원소가 인자로 전달되게 해야한다.
기술적으로는 스프레드 연산자가 그런 작업을 해준다.
하지만, 실제로는 전달하려는 배열 앞에 * 를 붙이기만 하면 된다.
fun main() {
val array : Array<String> = arrayOf("이식이", "원식이", "십식이")
spreadTest(array)
}
fun spreadTest(args : Array<String>) {
val list = listOf("삼식이", "팔식이", "구식이", *args)
println(list)
}
값의 쌍 다루기 : 중위호출과 구조 분해 선언
맵을 만들려면 mapOf 함수를 이용한다.
val map = mapOf(1 to "one", 2 to "two")
여기서 to 라는 게 코틀린 키워드가 아니다.
이 코드는 중위 호출(infix call)이라는 특별한 방식으로 to라는 일반 함수(메서드)를 호출한 것이다.
중위 호출 시에는 수신 객체와 유일한 메소드 인자 사이에 메소드 이름을 넣는다.
1.to("one") => "to" 메소드를 일반적인 방식으로 호출함.
1 to "one" => "to" 메소드를 중위 호출 방식으로 호출함.
인지가 하나뿐인 일반 메소드나, 인자가 하나 뿐인 확장 함수에 중위 호출을 사용할 수 있다.
함수(메서드)를 중위 호출에 사용하게 허용하고 싶다면, infix 변경자를 함수(메서드) 선언 앞에 추가하면 된다.
infix fun Any.to(other : Any) = Pair(this, other)
* Pair 는 코틀린 표준 라이브러리 클래스로, 그 이름대로 두 원소로 이뤄진 순서쌍을 표현한다.
이 to 함수는 Pair 의 인스턴스를 반환한다.
실제로 to는 제네릭 함수지만, 위 코드에서는 그런 세부사항을 생략한다.
// to 라는 내장함수를 이용해서 값을 저장
val(number, name) = 1 to "one"
위 코드는 구조 분해 선언이라고 부른다.
Pair 인스턴스 외 다른 객체에도 구조 분해를 적용할 수 있다.
// to 코틀린 내장 함수(API)
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
위 코드와 위 그림과 연관지어 보면 좋을 거 같다.
그리고 루프에서도 구조 분해 선언을 활용할 수 있다.
fun main() {
val collection : Collection<String> = setOf<String>("오늘은", "무슨요일?")
for ((idx, e) in collection.withIndex()) {
println("$idx : $e")
}
}
withIndex()를 구조 분해 선언과 조합하면 컬렉션 원소의 인덱스와 값을 따로 변수에 담을 수 있다.
마지막으로 listOf 와 마찬가지로 mapOf에도 원하는 개수만큼 인자를 전달할 수 있다.
하지만, mapOf의 경우에는 각 인자가 키와 값으로 이뤄진 순서쌍이어야 한다.
public fun <K, V> mapOf(vararg pairs: Pair<K, V>): Map<K, V> =
if (pairs.size > 0) pairs.toMap(LinkedHashMap(mapCapacity(pairs.size))) else emptyMap()
'Language > Kotlin' 카테고리의 다른 글
[Kotlin IN ACTION] - Kotlin 로컬 함수와 확장 (0) | 2022.07.21 |
---|---|
[Kotlin IN ACTION] - Kotlin 문자열 다루기(split) (0) | 2022.07.21 |
[Kotlin IN ACTION] - Kotlin 함수 정의와 호출(확장함수) (0) | 2022.07.18 |
[Kotlin IN ACTION] - Kotlin Exception (예외처리) (0) | 2022.07.14 |
[Kotlin IN ACITON] - Kotlin while & for loop (반복문) (0) | 2022.07.14 |