본문은 Effective Kotlin을 읽고 간단하게 정리한 글입니다. 필요에 따라 생략/수정된 부분이 있을 수 있으며, 내용이 추후 변경될 수 있습니다.
책에서는 아규먼트라고 나왔지만, 이름 있는 아규먼트(Named Argument)보다는 이름 있는 파라미터(Named Parameter)가 더 보편적인 표현이므로 본문에서는 해당 단어를 사용하고자 한다(사실 책에서도 혼용해서 사용한다..).
1. 이름 있는 파라미터의 장점
1) 값이 어떤 의미를 지니는지 명확하게 표현할 수 있다
// 각각의 아규먼트가 어떤 의미를 지니는지 불명확함
listOf("John", "Tom", "Paul").joinToString(",", "Class:", "!!")
// 보다 명확하게 의미를 파악할 수 있음
listOf("John", "Tom", "Paul").joinToString(separator = ",", prefix = "Class:", postfix = "!!")
2) 입력 순서에 상관없이 값을 넘길 수 있으므로 안전하다
먼저 joinToString 함수를 살펴보자. 같은 타입의 파라미터가 여러 개 존재하는 것을 확인할 수 있다.
public fun <T> Iterable<T>.joinToString(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String {
return joinTo(StringBuilder(), separator, prefix, postfix, limit, truncated, transform).toString()
}
이러한 이유로 순서를 바꿔서 함수를 호출하면 엉뚱한 결과가 나올 수 있다.
이때 이름 있는 파라미터를 사용하면 순서와 상관없이 값을 넘길 수 있게 된다.
// Class:John,Tom,Paul!!
listOf("John", "Tom", "Paul").joinToString(",", "Class:", "!!")
// ,John!!Tom!!PaulClass:
listOf("John", "Tom", "Paul").joinToString("!!", ",", "Class:")
// Class:John,Tom,Paul!!
listOf("John", "Tom", "Paul").joinToString(postfix = "!!", separator = ",", prefix = "Class:")
2. 이름 있는 파라미터를 사용하기 좋은 Case
1) 해당 파라미터가 디폴트 파라미터인 경우
일반적으로 함수 이름은 필수 파라미터들과 관련되어 있다. 그러나 디폴트 값을 갖는 옵션 파라미터의 경우는 그렇지 않은 경우가 많으므로 이름을 붙여서 사용하는 것이 좋다.
// greet 함수는 필수 파라미터인 "name"에만 관련되어 있음
fun greet(name: String, prefix: String = "~~~!!!"): String {
return "Hi, ${name}${prefix}"
}
greet("Michael", prefix = "....")
2) 같은 타입의 파라미터가 많은 경우
파라미터가 모두 다른 타입이라면 컴파일 시점에 잘못 입력한 아규먼트를 빠르게 찾아낼 수 있지만, 같은 타입이 많은 경우엔 문제를 발견하기 어려울 수 있다. 따라서 같은 타입의 파라미터가 많다면 이름있는 파라미터를 사용하는 게 좋다.
// CharSequence가 무려 4개, 특히 3개가 연속적으로 위치하고 있음
public fun <T> Iterable<T>.joinToString(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String {
return joinTo(StringBuilder(), separator, prefix, postfix, limit, truncated, transform).toString()
}
3) 함수 타입 파라미터가 있는 경우
함수 타입 파라미터가 있는 경우엔 이름 있는 파라미터를 사용하는 게 좋다.
// Bad
button({ /* 이벤트 리스너 */ }, { /* 버튼 빌더 */})
// Better
button(onClick = { /* 이벤트 리스너 */ }) {
{ /* 버튼 빌더 */})
}
특히 여러 함수 타입의 옵션 파라미터가 있는 경우엔 이름 있는 파라미터를 사용하는 게 좋다.
// https://github.com/ReactiveX/RxKotlin
fun main() {
val list = listOf("Alpha", "Beta", "Gamma", "Delta", "Epsilon")
list.toObservable() // extension function for Iterables
.filter { it.length >= 5 }
.subscribeBy( // named arguments for lambda Subscribers
onNext = { println(it) },
onError = { it.printStackTrace() },
onComplete = { println("Done!") }
)
}
그러나 예외적으로 함수 타입 파라미터가 마지막에 위치함과 동시에 함수명이 이러한 마지막 파라미터를 설명하는 경우에는 이름을 붙이지 않고 사용하는 것이 좋다. 이런 형태의 함수는 DSL에서 자주 나타난다.
inline fun repeat(times: Int, action: (Int) -> Unit)
repeat(3) { index ->
println("Hello with index $index")
}
fun thread(
start: Boolean = true,
isDaemon: Boolean = false,
contextClassLoader: ClassLoader? = null,
name: String? = null,
priority: Int = -1,
block: () -> Unit
): Thread
thread {
println("Hello World!")
}
'책 > Effective Kotlin' 카테고리의 다른 글
[이펙티브 코틀린] 아이템 42: compareTo의 규약을 지켜라 (0) | 2023.09.04 |
---|---|
[이펙티브 코틀린] 아이템 21: 일반적인 프로퍼티 패턴은 프로퍼티 위임으로 만들어라 (0) | 2023.08.02 |
[이펙티브 코틀린] 아이템16: 프로퍼티는 동작이 아니라 상태를 나타내야 한다 (0) | 2023.07.21 |
[이펙티브 코틀린] 아이템9: use를 사용하여 리소스를 닫아라 (0) | 2023.07.04 |
[이펙티브 코틀린] 아이템8: 적절하게 null을 처리하라 (0) | 2023.07.04 |