ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 12장 - 연산자 오버로드 할 때는 의미에 맞게 사용하라
    Kotlin/Effective Kotlin 요약 2023. 2. 10. 00:01
    728x90

    팩토리얼을 구하는 함수

    fun main() {
        print(6.factorial())
    }
    
    fun Int.factorial(): Int = (1..this).product()
    fun Iterable<Int>.product(): Int = fold(1) {acc, i -> acc * i}
    
    //출력결과 : 720

     

    팩토리얼은 다음과 같이 ! 기호를 사용해 표기하는 것을 우리는 알고 있습니다.

    코틀린은 이런 연산자를 지원하지 않지만 다음과 같이 연산자 오버로딩을 활용하면 만들어낼 수 있습니다.

     

    fun main() {
        print(!6)
        print(6.not())
    }
    operator fun Int.not() = factorial()
    fun Int.factorial(): Int = (1..this).product()
    fun Iterable<Int>.product(): Int = fold(1) {acc, i -> acc * i}

    이제 !기호로 팩토리얼을 표현할 수 있습니다.

     

    이렇게 해도 될까요? 안됩니다.

    이 함수의 이름은 not이며 논리 연산에 사용해야지 팩토리얼 연산에 사용하면 안 됩니다.

     

    코드를 이렇게 작성하면 굉장히 혼란스럽고 오해의 소지가 있습니다.

    6.not() 과 같은 코드는 어떻게 보이시나요?

     

    분명하지 않은 경우

    fun main() {
     val tripledHello = 3 * {print("Hello")}
     tripledHello()
    }
    operator  fun Int.times(operation: () -> Unit): () -> Unit =
        { repeat(this) {operation()} }

    다음과 같은 코드가 함수를 세 번 호출한다는 것을 쉽게 이해할 수 있을 수 있습니다.

    하지만 의미가 명확하지 않다면 infix를 활용한 확장 함수를 사용하는 것이 좋습니다.

    infix는 중위 함수입니다.

     

    하지만 사실 함수를 n번 호출하는 것은 다음과 같은 형태로 이미 stdlib에 구현되어 있습니다.

    repeat(3){println("Hello")}

     

    규칙을 무시해도 되는 경우

    DSL을 사용하는 경우에는 규칙을 무시해도 됩니다.

    고전적인 HTML DSL

    body{
    	div{
    		+ " Some text"
    	}
    }

    String.unaryPlus가 사용됐지만 상관없습니다.

     

    결론

    연산자 오버로딩은 의미가 명확하면 사용하지 않는 것이 좋습니다.

    대신 infix 확장 함수 또는 톱레벨 함수를 활용하세요

     

    728x90

    댓글

Designed by Tistory.