이 글은 Kotlin In Action을 참고 하였습니다.
더욱 자세한 설명이나 예제는 직접 책을 구매하여 확인 하시기 바랍니다
코틀린에서는 특정 연산자의 역할을 함수로 정의할 수 있습니다. 이를 convention이라고 합니다.
7.1.1 이항 산술 연산자 오버로딩
data class Point(val x: Int, val y: Int)
operator fun Point.plus(other: Point): Point {
return Point(x + other.x, y + other.y)
}
fun main(args: Array) {
val p1 = Point(10, 20)
val p2 = Point(30, 40)
println(p1 + p2)
}
operator라는 키워드로 함수 앞에 붙이고 연산자에 지정된 함수명인 plus를 사용하면 + 연산의 동작을 정의하게 됩니다.
operator 없이 plus()란 함수를 선언하고 만약 해당 기능을 이용한다면 operator가 필요하다는 에러를 뱉습니다.
보통 operator의 선언은 확장함수를 많이 사용합니다.
오버로딩이 가능한 연산자는 아래와 같습니다.
연산자 |
함수명 |
a+b |
plus |
a-b |
minus |
a*b |
times |
a/b |
div |
a%b |
v1.1 미만: mod, v1.1 이상: rem |
연산자 우선순위는 산술 연산자의 우선순위를 그대로 따릅니다.
자바에서 코틀린의 오버로딩된 함수를 당연히 호출할 수 있으며, 코틀린에서 자바의 함수를 호출할때 해당 이름과 파라미터 개수만 맞다면 연산자가 오버로딩 된것처럼 사용할 수 있습니다. (자바에는 operator 연산자를 붙일 수 없으므로)
연산자의 타입이 다르고 return값역시 다르게 설정해도 상관없이 동작합니다.
operator fun Point.times(scale: Double): Point {
return Point((x * scale).toInt(), (y * scale).toInt())
}
fun main(args: Array) {
val p = Point(10, 20)
println(p * 1.5)
}
또한 교환법칙이 성립하지 않으므로 a * 1.5와 1.5 * a는 같지 않습니다.
같게 하려면 operator fun Double.times(p: Point): Point {..}를 추가적으로 선언해야 합니다.
operator 함수도 오버로딩이 가능하기 때문에 같은 이름에 파라미터 타입이 서로 다른 연산자 함수를 여러개 만들 수 있습니다.
단 비트연산자는 오버로딩이 불가 하고, 대신 중위 함수를 제공합니다.
자바 bit operator |
코틀린 함수 |
<< |
shl |
>> |
shr |
>>> |
ushr |
& |
and |
| |
or |
^ |
xor |
~ |
inv |
println(0x0F and 0xF0)
println(0x0F or 0xF0)
println(0x1 shl 4)
7.1.2 복합 연산자
단 plus와 plusAssign 두개를 동시 구현하면 컴파일 오류가 발생합니다. (+ 에 대한 동작을 어떤걸 해야할지 모르기 때문이죠.)
코틀린은 컬렉션에도 해당 연산지를 제공합니다. 단 아래 규칙에 따릅니다.
- +, - 는 항상 새로운 collection을 반환한다
- mutable collection에서 +=, -=는 collection을 원소를 변경한다.(새로운 collection을 생성하지 않음)
- 불변 collection에서 +=, -=는 새로운 collection을 반환한다. 따라서 이를 받는 변수는 var로 선언되어야 한다
val list = arrayListOf(1,2)
list += 3 // 기존 list에 3 추가
val newList = list + listof(3,4)
7.1.3 단항 연산자
operator fun Point.unaryMinus(): Point {
return Point(-x, -y)
}
operator fun BigDecimal.inc() = this + BigDecimal.ONE
fun main(args: Array) {
val p = Point(10, 20)
println(-p)
var bd = BigDecimal.ZERO
println(bd++)
println(++bd)
}
표현 |
함수명 |
+a |
unaryPlus |
-a |
unaryMinus |
!a |
not |
++a, a++ |
inc |
--a, a-- |
dec |
++ 이나 --의 경우 inc(), dec()만 구현하면 알아서 전위와 후위 연산을 해줍니다.
7.2.1 equals
7.2.2 compareTo
a >= b -> a.compareTo(b) >= 0 과 같습니다.
class Person(val firstName: String, val lastName: String) : Comparable {
override fun compareTo(other: Person): Int {
return compareValuesBy(this, other,
Person::lastName, Person::firstName)
}
}
fun main(args: Array) {
val p1 = Person("Alice", "Smith")
val p2 = Person("Bob", "Johnson")
println(p1 < p2)
}
Comparable 내부에 compareTo() 역시 operator 키워드가 붙어있기 떄문에 override할때 operator 키워드를 붙여줄 필요는 없습니다.
compareValueBy(객체1, 객체2, 비교조건1, 비교조건2) 함수는 두개의 조건을 우선순위 비교조건에 따라 처리하는 함수 입니다.
1. 두객체 비교 equals -> 0
2. 비교조건1 사용 -> 0 이 안나올때까지 비교
3. 만약 비교조건1이 모두 0이라면 비교조건2 사용 -> 0이 안나올때까지 비교
compareValueBy()를 사용하기 보단 필요한 필드만 따로 비교하도록 만드는게 더 간결하고 좋을수도 있습니다.
'개발이야기 > Kotlin' 카테고리의 다른 글
[Kotlin] 코틀린 High order function (0) | 2018.05.09 |
---|---|
[Kotlin] 코틀린 연산자 오버로딩 #2 컬렉션, in, rangeTo, iterator, destructuring, Property delegation, by (0) | 2018.05.06 |
[Kotlin] 코틀린 Collection과 배열 (3) | 2018.05.02 |
[Kotlin] 코틀린 원시타입 - Unit, Nothing, Int, Boolean.. (1) | 2018.04.30 |
[Kotlin] 코틀린 null 처리 - ? ?. ?: !!, let, lateinit, 제너릭, 플랫폼 타입 (0) | 2018.04.28 |