티스토리 뷰
이름 있는 인자(Argument)를 사용하라.
val text = (1..10).joinToString("|")
물론 joinToString이라는 함수를 이전에 사용해본 적이 있는 경우 또는 추측을 통해서 짐작할 순 있습니다.
또는 IDE의 도움을 받아, 함수의 각 인자가 함수의 어떠한 파라미터로 전달되는지 이름을 시각적으로 확인할 수도 있습니다.
이는 개발자의 IDE 설정에 따라 다를 수 있습니다. joinToString 함수에서 “|” Argument가 어떠한 역할로 동작하는지를 알기 어렵습니다.
구분자(delimiter 또는 seperator)로 사용됩니다.
해결책 1. 변수를 사용하라.
val seperator = "|"
val text = (1..10).joinToString(seperator)
인자를 바로 전달하는 것이 아니라, 어떠한 역할을 하는지를 바탕으로 변수를 만들어, 전달하는 방법이 있습니다.
이 방법도 좋은 방법이지만, 해당 변수를 사용하지 않을 가능성 또한 있고, 원치 않게 해당 변수를 다른 곳에서 사용하는 경우 또한 발생할 수 있습니다.
위와 같이 전달하는 전달하는 인자가 함수 내에서 어떠한 의도로 사용되는지가 명확하지 않은 경우는 해당 인자에 이름을 지정하여 전달해줄 수 있습니다. 이를 이름 있는 인자(Named Argument)라고 합니다.
해결책 2. 이름 있는 인자(Named Argument)
val text = (1..10).joinToString(seperator = "|")
위와 같이 인자에 명시적으로 해당 Argument가 함수의 어떤 파라미터로 전달되는지 명확하게 하기 위하여 이름 있는 인자를 사용할 수 있습니다.
만약 해결책 1. 과 같이 변수를 사용한다고 하여도, 이름 있는 인자를 아래와 같이 함께 사용하는 것이 좋습니다.
val seperator = "|"
val text = (1..10).joinToString(seperator = seperator)
이름 있는 인자의 장점
1. 전달하는 인자가 어떠한 의도로 사용되는지를 알 수 있다.
위에서 살펴본 예제와 동일한 맥락의 예입니다.
sleep(100)
sleep 이라는 함수로 전달되는 100이라는 인자만 보고서는 100ms를 쉬는 것인지, 100s인지 알기가 쉽지 않습니다.
물론 관습적으로 해당 함수를 많이 사용해본 적이 있거나, 다른 언어에서 사용해보신 경험이 있다면 ms 단위이지 않을까? s 단위이지 않을까? 추측할 순 있습니다.
sleep(timeMillis = 100)
위와 같이 명시적으로 이름 있는 인자를 사용하면, 명확하게 의도를 알 수 있습니다.
2. 함수에 정의된 파라미터 순서와 상관없이 전달할 수 있다.
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()
}
위 함수가 어떠한 기능을 수행하는지는 중요하지 않습니다. 일반적으로 해당 함수를 호출하기 위해서 다음과 같이 순차적으로 인자를 전달하여야 하는데요.
val text = (1..10).joinToString("|", "[" , "]")
val text = (1..10).joinToString(separator = "|", prefix = "[" , postfix = "]")
// 이름 있는 인자 사용
1번째 줄처럼, 전달하는 각 인자의 의도가 명확하게 드러나지 않을 경우 2번째 줄 처럼, 이름 있는 인자를 사용할 수 있고, 사용하면 좋습니다.
여기서 특이한 점은 이름 있는 인자를 사용할 경우는 함수의 파라미터 시그니처에 정의된 순서의 제약을 받지 않는다는 점입니다.
val text = (1..10).joinToString(prefix = "[" , separator = "|", postfix = "]")
위 코드처럼 인자의 순서를 바꾸어 더 직관적(prefix, seperator, postfix 순서)으로 사용할 수도 있습니다.
이름 있는 인자를 언제 사용하면 좋을까?
많은 Usecase가 있을 수 있습니다.
1. 같은 타입의 파라미터가 많은 경우
val text = (1..10).joinToString("|", "[" , "]")
val text = (1..10).joinToString(separator = "|", prefix = "[" , postfix = "]")
위와 같이 함수 내에 전달하는 인자가 String으로 같은 타입이 많을 경우, 더욱더 의미가 모호해지게 되는데요. 이럴 경우 이름 있는 인자를 사용하면 좋습니다.
2. 디폴트 인자가 있는 경우
디폴트 인자의 경우는 필수적으로 전달하지 않아도 되는 인자이기 때문에, 전달한다면 이름을 붙여서 전달하는 것이 좋습니다.
3. 함수 타입의 파라미터가 있는 경우
아래와 같이 함수 타입의 파라미터가 마지막에 올 경우는 대부분의 경우 해당 블록이 어떠한 기능을 수행하는지 명확한 경우가 많으므로 굳이 사용할 필요는 없습니다.
public fun thread(
start: Boolean = true,
isDaemon: Boolean = false,
contextClassLoader: ClassLoader? = null,
name: String? = null,
priority: Int = -1,
block: () -> Unit // 함수 타입 파라미터가 마지막에 오는 경우
): Thread
thread {
// thread 본문
}
그렇지 않고 아래와 같이 함수에 함수 타입의 파라미터가 여러 개가 오는 경우는 각 함수 타입의 인자가 어떠한 의도를 가지고 수행하는지 알기 어렵습니다.
fun call(before: () -> Unit = {}, after: () -> Unit = {}) {
before()
println("middle")
after()
println("-------")
}
fun main() {
call({ println("CALL") }) // before 파라미터로 인자가 전달 됩니다.
call { println("CALL") } // after 파라미터로 인자가 전달 됩니다.
call({ println("after") }, { println("before") })
// 어느 부분이 before이고, 어느 부분이 after 일까요?
}
4. 저의 사용 Case
- 하나의 파라미터만 존재하고, 함수 명으로 합리적인 예측이 가능한 경우는 사용하지 않습니다.
- 2개 이상의 파라미터가 존재할 경우 거의 사용하는 것 같습니다.
이름 있는 인자를 무조건 사용할 수 있는 건 아니다?
이름 있는 인자는 Kotlin으로 작성된 함수에서만 사용할 수 있습니다. Java로 작성된 함수를 Kotlin에서 사용할 때는 이름 있는 인자를 사용할 수 없습니다.
만약 사용할 경우 다음과 같은 에러가 발생합니다.
Reference.
- Effective Kotlin, 마르친 모스 칼라 지음 | 윤인성 옮김, 인사이트
- Total
- Today
- Yesterday
- TDD
- 구현
- 우선순위큐
- dp
- JPA
- 오늘의집
- 스트림
- Java
- sql
- 스택
- 정렬
- 회고
- 알고리즘
- 코드 스니펫
- 프로그래머스
- 카카오
- kotlin
- set
- 문자열
- 쓰레드
- 탐욕법
- 연결리스트
- dfs
- BFS
- Uber
- 비트연산
- 해쉬
- dsu
- k8s
- 코딩인터뷰
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |