Kotlin 연산자 오버로딩(Operator overloading)

연산자 오버로딩(Operator overloading)

Kotlin에는 연산자 오버로딩(Operator overloading)이라는 것이 있다. 기존의 연산자를 다른 형태에 대해서도 사용할 수 있도록 확장하는 기능이다. 예를 들어 숫자를 표현하는 클래스가 있을때, 그 클래스의 인스턴스끼리, 더하기나 곱셈 등을 하는 경우도 있을 것이다. 이 때 메서드의 호출에 의한 기법이 아니라 연산자를 사용하여 a + b 처럼 작성할 수 있도록 해주는 것이 연산자 오버로딩이다.

연산자는 특정 시그니처를 가진 메서드와 일치한다. + 연산자를 fun plus(myInt: MyInt): MyInt와 같은 시그니처의 메소드를 정의함으로써 사용할 수 있게 된다. 즉, plus()minus() 등의 연산자 메소드를 정의하는 것으로, +- 등의 연산자를 정의 할 수 있다.

구체적인 예를 보면서 쉽게 설명하기 위해 아래와 같이 MyInt클래스를 정의한다. Int 값이 하나만 있는 간단한 클래스이다.

예제: plus 메소드가 정의된 MyInt 클래스

class MyInt(val value: Int) {
    fun plus(myInt: MyInt): MyInt =
         MyInt(value + myInt.value)
}

plus 메소드을 사용하면 자신과 다른 객체 MyInt를 더할 수 있다. 그리고, 이 plus 메소드에 의해 + 연산자를 사용할 수 있게 된다.

예제: + 연산자 사용 가능

// 일반 메소드 호출에 의한 기법
val sum = MyInt(3).plus(MyInt(5))
println(sum.value) // => 8

// 연산자를 사용한 기법
val sum2 = MyInt(2) + MyInt(7)
println(sum2.value) // => 9

연산자 확장 함수

아래는 또 다른 흥미로운 예를 보여준다. 연산자에 해당하는 메서드는 확장 함수로 정의할 수도 있다. 아래에서는 확장 함수로 StringBuilderplusAssign메소드를 추가하고 있다. 이 plusAssign 메소드는 += 연산자에 해당한다⁠.

예제: += 연산자에 해당하는 확장 함수

fun StringBuilder.plusAssign(any: Any) {
  append(any)
}

Listing 29 += 연산자 사용 가능

val sb = StringBuilder()
sb += "I"
sb += " am"
sb += " Taro"
println(sb) // => I am Taro

그 외의 연산자와 그 메소드 시그니쳐

연산자와 연산자 메소드 시그니쳐는 다음과 같다.

a + b          a.plus(b)
a - b          a.minus(b)
a * b          a.times(b)
a / b          a.div(b)
a % b          a.rem(b)  // mod()에서 rem()로 변경 
a += b         a.plusAssign(b)
a -= b         a.minusAssign(b)
a *= b         a.timesAssign(b)
a /= b         a.divAssign(b)
a %= b         a.modAssign(b)
+a             a.unaryPlus()
-a             a.unaryMinus()
!a             a.not()
++a            a.inc()
--a            a.dec()
a == b         a?.equals(b) ?: (b === null)
a != b         !(a?.equals(b) ?: (b === null))
a < b          a.compareTo(b) > 0
a > b          a.compareTo(b) < 0
a <= b         a.compareTo(b) >= 0
a >= b         a.compareTo(b) <= 0
!var           a.not()
a..b           a.rangeTo(b)
a in b         a.contains(b)
a !in b        !a.contains(b)
a[i]           a.get(i)
a[i, j]        a.get(i, j)
a[i] = b       a.set(i, b)
a[i, j] = b    a.set(i, j, b)
a()            a.invoke()
a(i)           a.invoke(i)
a(i, j)        a.invoke(i, j)

참조