[출처 - Kotlin In Action] [아래 내용들은 Kotlin In Action을 공부하면서 스스로 정리한 내용입니다]
이번에 살펴볼 내용은 다음과 같습니다.
- vararg 키워드를 사용하면 호출 시 인자 개수가 달라질 수 있는 함수를 정의할 수 있다.
- 중위(infix) 함수 호출 구문을 사용하면 인자가 하나뿐인 메소드를 간편하게 호출 할 수 있다.
- 구조 분해 선언을 사용하면 복합적인 값을 분해해서 여러 변수에 나눠 담을 수 있다.
자바 컬렉션 API 확장
kotlin은 자바와 같은 컬렉션 클래스를 사용하지만 더 확장된 API를 제공합니다. 예를 들어
fun main(args: Array<String>) {
val strings:List<String> = listOf("First","Second","Third")
println(strings.last())
val numbers : List<Int> = listOf(1,14,2)
println(numbers.max())
}
이렇게 해서 리스트의 마지막 원소나, 가장 큰 값을 획득할 수 있습니다.(결과는 Third와 14 입니다.)
이것이 가능한 이유는 위의 Last와 max는 확장함수이기 때문입니다. 두 함수의 원본을 확인해 보겠습니다.
public fun <T> List<T>.last(): T {
if (isEmpty())
throw NoSuchElementException("List is empty.")
return this[lastIndex]
}
public fun <T : Comparable<T>> Iterable<T>.max(): 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
}
이렇게 last와 max가 확장함수로 _Collctions.kt에 정의 되어 있습니다. kotlin의 이런 표준 라이브러리 확장 함수는 last나 max 뿐만 아니라, 훨씬 많이 존재하지만 이런 것들을 모두 알 필요는 없고, 개발툴에서 코드완성 기능을 통해 확인하고 필요한 기능을 사용하시면 됩니다.
가변 인자 함수 : 인자의 개수가 달라질 수 있는 함수 정의
리스트를 생성하는 listof 함수의 정의를 보면 다음과 같습니다.
public fun <T> listOf(vararg elements: T): List<T>
vararg인자는 가변 길이 인자로 , 메소드를 호출할 때 원하는 개수만큼 값을 인자로 넘기면 자바 컴파일러가 배열에 그 값들을 넣어주는 기능을 합니다. 사용 방법은 파라미터 앞에 vararg를 붙입니다.
배열에 들어있는 원소를 가변 길이 인자로 넘길떄 자바는 그냥 넘지만, 코들린의 경우에는 명시적으로 풀어서 배열의 각 원소가 인자로 전되게 해야하는데 이 부분은 스프레드 연산자가 대신해줍니다. 스프레드 연산자가 대신해준다고 했지만 개발자는 배열 앞에 *를 붙여 주기만 하면 됩니다.
값의 쌍 다루기 : 중위 호출과 구조 분해 선언
다음 코드를 보면
val map = mapOf(1 to "one", 2 to "two", 3 to "three")
to 라는 단어가 있습니다. 이 to 라는 단어는 코틀린 키워드가 아니고 중위 호출이라는 방식으로 to 라는 일반 메소드를 호출 한 것입니다.
1.to("one")
1 to "one"
위의 두 코드는 같은 방식으로 첫번째는 to 메소드를 일반 방식으로 호출한 것이고 두번째는 to 메소드를 중위 호출 방식으로 호출한 것입니다.
즉, 중위호출은 인자가 하나뿐인 일반 메소드나 인자가 하나뿐인 확장함수에서 사용할 수 있습니다. 그리고 함수를 중위호출에 사용하게 허용하려면 함수 선언 앞에 infix라는 변경자를 추가해야 합니다.
infix fun Any.to(other:Any) = Pair(this,other)
위의 to 함수는 Pair 인스턴스를 반환합니다. (Pair는 코들린 표준라이브러리로 여기서 확인 하시면 됩니다. 그리고 to는 제너릭 함수지만 설명을 위해 세부 사항은 생략했습니다.)
위의 to를 사용해보면
fun main(args: Array<String>) {
val (number, name) = 1 to "one"
println("number: $number")
println("name: $name")
}
infix fun Any.to(other:Any) = Pair(this,other)
결과는
number: 1
name: one
그리고 위의 val (number, name) = 1 to "one"을 구조 분해 선언이라 부릅니다. 왜 그렇게 되는지 위의 code를 통해 설명 드리면 1 과 "one"이 to를 통해 Pair가 되고 이 Pair의 값들이 val (number,name)의 각각에 들어가게 됩니다.
Pair 인스턴스 외 다른 객체에도 구조 분해를 적용할 수 있습니다. 예를 들어 key와 value라는 두 변수를 map의 원소로 사용해 초기화 할 수 있습니다.
또한 withIndex를 사용하여 루프에서 구조분해선언을 활용할 수 있습니다.
fun main(){
val strings = listOf("first", "second", "fourteenth")
for((index,element) in strings.withIndex()){
println("$index: $element")
}
}
0: first
1: second
2: fourteenth
정리하면 to 함수는 확장 함수이고, to를 사용하면 타입과 관련 없이 임의의 순서쌍을 만들수 있습니다. 이는 to의 수신 객체가 제네릭하다는 뜻입니다.
'2023년 이전 > kotlin' 카테고리의 다른 글
kotlin - 로컬 함수와 확장 (0) | 2020.02.20 |
---|---|
kotlin - 문자열과 정규식 다루기 (0) | 2020.02.20 |
Kotlin - 확장 함수 와 확장 프로퍼티 (0) | 2020.02.19 |
Kotlin - 함수를 호출하기 쉽게 만들기 (0) | 2020.02.19 |
코틀린(Kotlin)- 코틀린에서 컬렉션 만들기 (0) | 2020.02.19 |