val map = hashMapOf(1 to "one", 7 to "seven")

위 코드는 컬렉션을 만들고 K, V 형식으로 데이터를 매핑해주고 있다. 여기서 to 는 코틀린 언어가 제공해주는 키워드가 아니라, **일반 함수**이다.

코틀린은 자신만의 컬렉션 기능을 제공하지 않는다. → 자바의 컬렉션과 상호작용함

하지만 코틀린에선 자바보다 더 많은 기능을 쓸 수 있다. ex) 리스트의 마지막 원소를 가져오는 last()

함수를 호출하기 쉽게 만들기

자바 컬렉션에는 디폴트 toString() 구현이 들어있다. 하지만 toString() 은 출력형식이 고정되어 있고 우리에게 필요한 형식이 아닐 수도 있다.

val list = listOf(1, 2, 3)
println(list)

출력 : [1, 2, 3]

출력된 [1, 2, 3]을 (1; 2; 3;)처럼 바꾸고 싶다면 어떻게 해야할까?

fun <T> joinToString(
		collection: Collection<T>,
		separator: String = ", ",
		prefix: String = "",
		postfix: String = ""
): String {
		val result = StringBuilder(prefix)
		
		for((index, element) in collection.withIndex()) {
				if(index > 0) result.append(separator)
				result.append(element)
		}
		result.append(postfix)
		return result.toString()
}

println(joinToString(list, "; ", "(", ")")) // (1; 2; 3)
println(joinToString(list, separator = "; ", prefix = "(", pstfix = ")")) // (1; 2; 3)
println(joinToString(list) // 1, 2, 3

디폴트 파라미터를 사용해서 함수의 오버로딩을 줄여 중복을 없애고, 이름 붙인 인자를 사용하여 가독성이 좋게 만들 수 있다.

확장 함수

확장 함수를 만들려면 추가하려는 함수 이름 앞에 해당 함수가 확장할 클래스의 이름을 붙이면 된다.

여기서 클래스 이름을 **수신 객체 타입(receiver type)**이라 부르며, 확장 함수가 호출되는 대상이 되는 값(객체)을

**수신 객체(receiver object)**라고 부른다.

fun **String**.lastChar(): Char = **this**.get(**this**.length-1) // this 생략 가능
fun **String**.lastChar(): Char = get(length-1)

println("Kotlin".lastChar()) // "n"

확장 함수 내부에선 일반적인 인스턴스 메소드의 내부에서와 마찬가지로 수신 객체의 메소드나 프로퍼티를 바로 사용할 수 있다.

확장함수를 사용해서 joinToString 을 다시 만들어보자.