Operator overloading
Kotlin은 미리 정의한 연산자 의 구현을 제공 가능하다. 이 연산자는 (예: +
또는 *
) 고정된 우선순위가 고정되어 있다. 연산자를 구현하려면 고정된 이름을 가진 멤버 함수 또는 확장 함수를 제공한다. 연사자를 오버로딩하는 함수는 operator
제한자로 지정한다.
규약
서로 다른 연산자에 대한 연산자 오버로딩을 규정하는 규칙을 설명
단항 연산자
식 | 변환 |
---|---|
+a | a.unaryPlus() |
-a | a.unaryMinus() |
!a | a.not() |
예를 들어 컴파일러는 +a
식을 다음 단계를 따라 수행한다.
- a 의 타입을 결정한
- 리시버
T
에 대해 파라미터를 갖지않고operator
제한자로 지정한unaryPlus()
함수(멤버함수 또는 확장함수)를 찾는다 - 함수가 없거나 모호한 경우 컴파일러 에러를 낸다
- 함수가 존재하고 그 리턴 타입이
R
이라면, 식+a
는 타입R
을 가진다
기본 타입에 맞게 최적화 되어 있어 함수 호출에 대한 오버헤드가 발생하지 않는다.
식 | 변환 |
---|---|
a++ | a.inc() + 아래 참고 |
a-- | a.dec() + 아래 참고 |
inc
또는 dec
이 호출된 객체를 변경해서는 안된다. inc()
및 dec()
함수는 ++
또는 --
연산이 사용된 변수에 할당 될 값을 반환해야한다.
컴파일러는 접미사 타입(a++
) 의 연산자를 해결하기 위해 다음 단계를 수행한다.
a
타입을 결정한다. 타입을T
라고 가정한다.- 리시버
T
에 대해 파라미터를 갖지않고operator
제한자로 지정한inc()
함수를 찾는다 - 함수의 반환 타입이
T
의 하위 타입인지 확인한다.
식의 계산 결과는 다음과 같다
a
의 초기값을 임시 저장소a0
에 저장한다a.inc()
의 결과를a
에 할당한다- 식의 결과로
a0
를 리턴한다
a--
의 단계도 완전히 유사하다
++a
와 --a
와 같은 접두사 타입의 방식으로 작동하며, 결과는 다음과 같다.
a.inc()
의 결과를a
에 할당한다- 식의 결과로
a
의 새로운 값을 돌려준다
이항 연산
식 | 변환 |
---|---|
a + b | a.plub(b) |
a - b | a.minus(b) |
a * b | a.times(b) |
a / b | a.div(b) |
a % b | a.rem(b), a.mod(b), (deprecated) |
a..b | a.rangeTo(b) |
이 표의 연산에서 컴파일러는 변환 열의 식을 실행한다
rem
연산자는 Kotlin 1.1부터 지원된다. Kotlin 1.0까지만 mod
연산자를 사용한다.
식 | 변환 |
---|---|
a in b | b.contains(a) |
a !in b | !b.contains(a) |
in
과 !in
의 경우 절차는 동일하지만 인자의 순서는 반대이다.
식 | 변환 |
---|---|
a[i] | a.get(i) |
a[i, j] | a.get(i, j) |
a[i_1, ..., i_n] | a.get(i_1, ..., i_n) |
a[i] = b | a.set(i, b) |
a[i, j] = b | a.set(i, j, b) |
a[i_1, ..., i_n] = b | a.set(i_1, ..., i_n, b) |
대괄호는 해당 개수만큼 인자를 가진 get
과 set
메소드 호출로 변환된다.
식 | 변환 |
---|---|
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 += b
같은 동작은 다음 단계를 수행한다
- 오른쪽 열의 함수를 사용할 수 있는 경우
- 해당 이항 함수 (
plusAssign()
의 경우plus()
)도 사용할 수 있는 경우 에러를 발생한다 (모호성) - 반환 타입이
Unit
인지 확인하고, 아닌 경우 에러를 발생한다 a.plusAssign(b)
코드를 생성
- 해당 이항 함수 (
- 그렇지 않으면,
a = a + b
코드 생성을 시도한다 (이것은 타입 검사를 포함한다.a + b
의 타입은a
의 하위타입어야야 한다)
주의 : 할당은 Kotlin 에서 식(expressions) 이 아니다
식 | 변환 |
---|---|
a == b | a?.equals(b) ?: (b === null) |
a != b | !(a?.equals(b) ?: (b === null) |
참고 : === 및 !== (동일성 검사)는 오버로딩할 수 없으므로 규칙이 없다
==
연산은 특별하다. null 을 필터링하여 null == null
이 항상 true이며, null 이 아닌 x 에 대한 x == null
은 항상 false 이고 x.equals()
를 호출하지 않는다.
식 | 변환 |
---|---|
a > b | a.compareTo(b) > 0 |
a < b | a.compareTo(b) < 0 |
a >= b | a.compareTo(b) >= 0 |
a <= b | a.compareTo(b) <= 0 |
모든 비교는 compareTo
에 대한 호출로 바뀌며 Int
를 반환하는데 필요하다.
네임드 함수에 대한 중위 호출
중위 함수 호출을 사용하여 커스텀 중위 연산을 시뮬레이션 가능하다.