Post

Kotlin in action 03. 함수 정의와 호출

chapter03. 함수 정의와 호출

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

자바 컬렉션의 toString을 커스텀하게 처리할 수 있는 함수 joinToString 를 코틀린 답게 구현해보자.

joinToString() 함수 초기 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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()
}

// 호출
fun main() {
    joinSoTring(collection, " ", " ", ".")
}

코틀린에서는 함수에 전달하는 인자 중 일부(또는 전부)의 이름을 명시할 수 있다.

1
2
// 전달 인자를 명시하여 오류 방지 및 가독성 증진이 가능하다.
joinSoTring(collection, seperator = " ", prefix = " ", postfix = ".")

3.2.2 디폴드 파라미터 값

  • 코틀린에서는 함수 선언에서 파라미터의 디폴트 값을 지정할 수 있으므로 오버로드를 줄일 수 있다. ```kotlin fun joinToString( collection: Collection, separator: String = ", ", prefix: String = "", postfix: String = "" ): String { // ... 생략 }

// 호출 fun main() { val list = listOf(1, 2, 3) joinSoTring(list, “, “, “”, “”) // 1, 2, 3 joinSoTring(list) // 1, 2, 3 joinSoTring(list, “; “) // 1; 2; 3 }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> 디폴트 값과 자바
> 
> 자바에는 디폴트 파라미터가 없어 코틀린 함수가 디폴트 파라미터를 제공하더라도 모든 인자를 명시해야 한다.
> 
> @JvmOverloads 애너테이션을 추가하면 코틀린 컴파일러가 자동으로 맨 마지막 파라미터로부터 파라미터를 하나씩 생략한 오버로딩한 자바 메서드를 추가해준다.

#### 3.2.3 정적인 유틸리티 클래스 없애기: 최상위 함수와 프로퍼티

#### 최상위 함수

코틀린에서는 함수를 소스 파일의 최상위 수준, 클래스 밖에 위치 시킬 수 있다.
```kotlin
package strings

fun joinToString(/* 생략 */) : String { /* 생략 */ }

JVM이 클래스 안에 들어있는 코드만 실행할 수 있기 때문에 컴파일러는 이 파일을 컴파일할 때 새로운 클래스를 정의해준다.

1
2
3
4
package strings;
public class JoinKt { //join.kt -> 코틀린 소스 파일 이름과 자바 클래스 이름이 대응된다.
    public static String joinToString(/* 생략 */) { /* 생략 */ }
}

최상위 프로퍼티

프로퍼티 또한 최상위 수준에 둘 수 있다. 이 때 값은 정적 필드에 저장된다.

1
2
3
4
5
6
7
8
var opCount = 0
fun performOperation() {
    opCount++
    // ...
}
fun reportOperationCount() {
    println("Operation performed $opCount times")
}
  • 최상위 프로퍼티도 다른 프로퍼티처럼 접근자 메서드를 통해 자바 코드에 노출된다.
  • const 변경자를 추가하면 프로퍼티를 public static final 필드로 컴파일하게 만들 수 있다.
    • primitive 타입String 타입만 const로 지정할 수 있다.

3.3 메서드를 다른 클래스에 추가: 확장 함수와 확장 프로퍼티

확장 함수

  • 어떤 클래스의 멤버 메서드인 것처럼 호출할 수 있지만 그 클래스의 밖에 선언된 함수다.
  • 확장 함수를 만들려면 추가하려는 함수 이름 앞에 그 함수가 확장할 클래스 이름을 붙이면 된다.
    • 수신 객체 타입(receiver type): 클래스 이름
    • 수신 객체(receiver object): 확장 함수가 호출되는 대상이 되는 값(객체)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fun <T> Collection<T>.joinToString( // Collection<T>에 대한 확장 함수를 선언
    separator: String = ", ",
    prefix: String = "",
    postfix: String = ""
): String {
    val result = StringBuilder(prefix)
    for ((index, element) in this.withIndex()) { // "this" 는 수신 객체를 기리킨다. 여기는 T 타입의 원소 컬렉션
        if (index > 0) result.append(separator)
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}

// 호출
fun main() {
    val list = listOf(1, 2, 3)
    println(list.joinToString(separator = "; ", prefix = "(", postfix = ")"))
}

확장 함수는 오버라이드 할 수 없다.

  • 확장 함수는 클래스의 일부가 아니다. 확장 함수는 클래스 밖에 선언된다.
  • 확장 함수가 정적 메서드와 같은 특성을 가지므로 확장 함수를 하위 클래스에서 오버라이드할 수 없다.

확장 프로퍼티

1
val String.lastChar: Char get() = get(length - 1)
  • 확장 프로퍼티를 사용하면 기존 클래스 객체에 대한 프로퍼티 형식의 구문으로 사용할 수 있는 API를 추가할 수 있다.
  • 프로퍼티라는 이름으로 불리기는 하지만 상태를 저장할 적절한 방법이 없기 때문에 실제로 확장 프로퍼티는 아무 상태도 가질 수 없다.
  • 하지만 프로퍼티 문법으로 더 짧게 코드를 작성할 수 있어서 편한 경우가 있다.

3.4 컬렉션 처리: 가변 길이 인자, 중위 함수 호출, 라이브러리 지원

코틀린은 다음과 같은 특성이 있다.

  • varag 키워드를 사용하면 호출시 인자 개수가 달라질 수 있는 함수를 정의할 수 있다.
  • 중위 함수 호출 구문을 사용하면 인자가 하나뿐인 메소드를 간편하게 호출할 수 있다.
  • 구조 분해 선언을 사용하면 복합적인 분해해서 여러 변수에 나눠 담을 수 있다

가변 인자 함수

가변 길이 인자는 메소드를 호출할 때 원하는 개수만큼 값을 인자로 넘기면 자바 컴파일러가 배열에 그 값들을 넣어주는 기능이다.

코틀린은 파라미터 앞에 vararg 변경자를 붙인다

이미 배열에 들어있는 원소를 가변 길이 인자로 넘기려면 배열을 명시적으로 풀어서 배열의 각 원소가 인자로 전달되게 해야 한다. (스프레드 연산자)

1
2
3
fun main(args: Array<String>) {
    val list = listOf("args: ", *args)
}

중위 호출

코틀린에는 함수 호출의 가독성을 향상시킬 수 있는 방법 중 하나로 중위 호출 방식이 있다.

1
2
3
1.to("one") // "to"  메서드를 일반적인 방식으로 호출

1 to "one" // "to" 메서드를 중위 호출 방식으로 호출
  • 중위 호출 시에는 수신 객체와 유일한 메서드 인자 사이에 메서드 이름을 넣는다.
1
infix fun Any.to(other: Any) = Pair(this, other)
  • 함수를 중위 호출이 가능하게 하려면 infix 변경자를 함수 선언 앞에 추가 하면 된다.

구조 분해 선언

구조 분해를 사용해 여러 변수를 초기화할 수 있다.

1
val (number, name) = 1 to "one" //두 변수를 즉시 초기화할 수 있다.
This post is licensed under CC BY 4.0 by the author.