안드로이드 개발자 노트
[이펙티브 코틀린] Item12. 연산자 오버로드를 할 때는 의미에 맞게 사용하라 본문
반응형
연산자 오버로딩은 굉장히 강력한 기능이지만, 위험할 수 있습니다.
예를 들어 팩토리얼을 구하는 함수를 생각해 봅시다.
fun Int.factorial(): Int = (1..this).product()
fun Iterable<Int>.product(): Int =
fold(1) { acc, i -> acc * i }
이 함수는 Int로 정의되어 있으므로, 편리하게 사용할 수 있습니다.
print(10 * 6.factorial()) // 7200
팩토리얼은 ! 기호를 사용해 표기합니다.
다음과 같이 연산자 오버로딩을 활용하면, 만들어낼 수 있습니다.
operator fun Int.not() = factorial()
print(10 * !6) // 7200
하지만 함수의 이름이 not이므로 논리연산에 맞게 사용해야지, 팩토리얼 연산에 사용하면 안됩니다.
관례에 어긋나기 때문입니다.
이는 구체적인 이름을 가진 함수이며, 모든 연산자가 이러한 이름이 나타내는 역할을 할 거라고 기대됩니다.
분명하지 않은 경우
관례를 충족하는지 아닌지 확실하지 않을 때가 문제입니다.
예를들어 함수를 곱한다는 것 (* 연산자)의 의미를 두가지로 해석할 수 있습니다.
- 새로운 함수(() → Unit)를 만들어 낸다.
- 같은 함수를 n번 호출한다.
의미가 명확하지 않다면, infix를 활용한 확장 함수를 사용하는 것이 좋습니다.
일반적인 이항 연산자 형태처럼 사용할 수 있습니다.
infix fun Int.timesRepeated(operation: ()->Unit) = {
repeat(this) { operation() }
}
val tripledHello = 3 timesRepeated { print("Hello") } // 이항 연산자 처럼 사용
tripleHello() // 출력 : HelloHelloHello
톱레벨 함수(top-level function)을 사용하는 것도 좋습니다.
repeat(3) { print("Hello") } // 출력: HelloHelloHello
규칙을 무시해도 되는 경우
지금까지 설명한 연산자 오버로딩 규칙을 무시해도 되는 경우가 있습니다.
바로 도메인 특화 언어(Domain Specific Language, DSL)를 설계할 때 이며, 해당 도메인을 위해 설계된 DSL 이기 때문에 이러한 규칙을 무시할 수 있습니다.
// HTML DSL. 코틀린 문법을 활용해서 만든 DSL
body {
div {
+"Some Text"
}
}
문자열 앞에 String.unaryPlus가 사용된 것을 볼 수 있습니다.
정리
- 연산자 오버로딩은 그 이름의 의미에 맞게 사용해야 한다.
- 연산자 의미가 명확하지 않다면, 연산자 오버로딩을 사용하지 않는 것이 좋다. 대신 일반 함수를 사용하길 바란다.
- 꼭 연산자 같은 형태로 사용하고 싶다면 Infix 확장 함수 또는 톱레벨 함수를 활용하는 것이 좋다.
반응형
'Kotlin > 이펙티브 코틀린' 카테고리의 다른 글
[이펙티브 코틀린] Item13. Unit?을 리턴하지 말라 (0) | 2023.10.01 |
---|---|
[이펙티브 코틀린] item11. 가독성을 목표로 설계하라 (0) | 2023.09.24 |
[이펙티브 코틀린] item10. 단위 테스트를 만들어라 (0) | 2023.09.16 |