728x90
반응형
✅ 연산자 오버로딩과 기타 관례
- 언어 기능을 타입에 의존하는 자바와 달리 코틀린은 함수 이름을 통한 관례에 의존한다.
- 코틀린이 이런 관례를 채택한 이유는 기존 자바 클래스를 코틀린 언어에 적용하기 위함이다.
- 기존 자바 클래스에 대해 확장 함수를 구현하면서 관례에 따라 이름을 붙이면 기존 자바 코드를 바꾸지 않아도 새로운 기능을 쉽게 부여할 수 있다.
- 이번 절에서는 코틀린이 지원하는 여러 관례와 그 관례의 사용법에 대해 알아본다.
✅ 산술 연산자 오버로딩
- 코틀린에서 관례를 사용하는 가장 단순한 예는 산술 연산자이다.
- 자바에서는 원시 타입에 대해서만 산술 연산자를 사용할 수 있고, 추가로 String에 대해 + 연산자를 사용할 수 있다.
- 다른 클래스에서도 산술 연산자를 유용하게 사용하면 어떨까??
- 컬렉션에 원소를 추가할 때 += 연산자를 사용할 수 있다면??
- 다른 클래스에서도 산술 연산자를 유용하게 사용하면 어떨까??
- 코틀린에서는 이러한 일이 가능하다.
📌 이항 산술 연산 오버로딩
/* PLUS 연산자 구현하기 */
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point) : Point { // "plus"라는 이름의 연산자 함수를 정의한다.
return Point(x + other.x, y + other.y) // 좌표를 성분별로 더한 새로운 점을 반환한다.
}
}
val p1 = Point(10, 20)
val p2 = Point(30, 40)
println(p1 + p2) // +로 계산하면 "plus" 함수가 호출된다.
// Point(x=40, x=60)
- 위의 예제와 같이 plus 함수 앞에 operator 키워드를 붙여 오버로딩하여 사용할 수 있다.
- 연산자를 오버로딩하는 함수 앞에는 꼭 operator가 있어야 한다.
- operator 키워드를 붙임으로써 어떤 함수가 관례를 따르는 함수임을 명확히 할 수 있다.
- plus 말고도 다른 산술 연산자 모두 가능하다.
- operator 변경자를 추가해 plus 함수를 선언하고 나면 + 기호로 두 Point 객체를 더할 수 있다.
- 연산자를 멤버 함수로 만드는 대신 확장 함수로 정의할 수도 있다.
/* 연산자를 확장 함수로 정의하기 */
operator fun Point.plus(other: Point): Point {
return Point(x + other.x, y + other.y)
}
- 위의 예제는 앞의 구현과 똑같으며, 외부 함수의 클래스에 대한 연산자를 정의할 때는 관례를 따르는 이름의 확장 함수로 구현하는게 일반적인 패턴이다.
- 다른 어넝와 비교할 때 코틀린에서 오버로딩한 연산자를 정의하고 사용하기가 더 쉽다.
- 코틀린에서는 프로그래머가 직접 연산자를 만들어 사용할 수 없으며 언어에서 미리 정해둔 연산자만 오버로딩할 수 있다.
- 또한, 관례에 따르기 위해 클래스에서 정의해야 하는 이름이 연산자별로 정해져 있다.
- 아래 표는 코틀린에서 정의할 수 있는 이항 연산자와 그에 상응하는 연산자 함수 이름을 보여준다.
식 | 함수 이름 |
a * b | times |
a / b | div |
a % b | mod(1.1부터 rem) |
a + b | plus |
a - b | minus |
- 또한 연산자를 정의할 때 두 피연산자가 같은 타입일 필요는 없다.
/* 두 피연산자의 타입이 다른 연산자 정의하기 */
operator fun Point.times(scale: Double) : Point {
return Point((x * sacle).toInt(), (y * scale).toInt())
}
val p = Point(10, 20)
println(p * 1.5)
// Point(x=15, y=30)
- 그리고 연산자 함수의 반환 타입이 꼭 두 피연산자 중 하나와 일치해야 하는 것도 아니다.
/* 결과 타입이 피연산자 타입과 다른 연산자 정의하기 */
operator fun Char.times(count: Int) : String {
return toString().repear(count)
}
println('a' * 3)
// aaa
📌 복합 대입 연산자 오버로딩
- plus와 같은 연산자를 오버로딩하면 코틀린은 + 연산자뿐 아니라 그와 관련 있는 연산자인 += 도 자동으로 함께 지원한다.
- 이때, +=, -= 등의 연산자는 복합 대입 연산자라 불린다.
var point = Point(1,2)
point += Point(3, 4)
println(point)
// Poinrt(x=4, y=6)
- point += Point(3,4)는 point = point + Point(3, 4)라고 쓴 식과 같다.
- 이러한 복합 대입 연산자를 활용한 연산은 변수가 변경 가능한 경우에만 사용할 수 있다.
- 경우에 따라 += 연산이 객체에 대한 참조를 다른 참조로 바꾸기보다 원래 객체의 내부 상태를 변경하게 만들고 싶을 때가 있다.
- 변경 가능한 컬렉션에 원소를 추가하는 경우가 대표적
- 이러한 경우에도 복합 대입 연산자를 활용하면 간편하게 상태를 변경할 수 있다.
val numbers = ArrayList<Int>()
numbers += 42
println(numbers[0])
// 42
- 이외에도 코틀린 표준 라이브러리는 컬렉션에 대해 두 가지 접근 방법을 함께 제공한다.
- +와 -는 항상 새로운 컬렉션을 반환하며, +=와 -=연산자는 항상 변경 가능한 컬렉션에 작용해 메모리에 있는 객체 상태를 변화시킨다.
- 또한 읽기 전용 컬렉션에서 +=와 -=는 변경을 적용한 복사본을 반환한다.
- 이런 연산을 통해 개별 원소를 사용하거나 원소 타입이 일치하는 다른 컬렉션을 사용할 수 있다.
- 예제를 통해 이를 알아보자.
val list = arrayListOf(1, 2)
list += 3 // +=는 "list"를 변경한다.
val newList = list + listOf(4, 5) // +는 두 리스트의 모든 원소를 포함하는 새로운 리스트를 반환한다.
println(list)
// [1, 2, 3]
println(newList)
// [1, 2, 3, 4, 5]
📌 단항 연산자 오버로딩
- 코틀린은 -a와 같이 한 값에만 적용하는 단항 연산자도 제공한다.
- 단항 연산자를 오버로딩하는 절차도 이항 연산자와 같다.
- 미리 정해진 이름의 함수를 선언하면서 operator로 표시하면 된다.
/* 단항 연산자 정의하기 */
operator fun Point.unaryMinus() : Point { // 단항 minus(음수) 함수는 파라미터가 없다.
return Point(-x, -y) // 좌표에서 각 성분의 음수를 취한 새 점을 반환한다.
}
val p = Point(10, 20)
println(-p)
// Point(x=-10, y=-20)
- 단항 연산자를 오버로딩하기 위해 사용하는 함수는 인자를 취하지 않는다.
- 아래 표는 코틀린에서 오버로딩할 수 있는 모든 단항 연산자를 보여준다.
식 | 함수 이름 |
+a | unaryPlus |
-a | unaryMinus |
!a | not |
++a, a++ | inc |
--a, a-- | dec |
- inc나 dec 함수를 정의해 증가 / 감소 연산자를 오버로딩하는 경우 컴파일러는 일반적인 값에 대한 전위와 후위 증가 / 감소 연산자와 같은 의미를 제공한다.
- 전위 / 후위에 대한 연산은 자동으로 이루어진다.
/* 증가 연산자 정의하기 */
operator fun BigDecimal.inc() = this + 1
var bd = BigDecimal.ZERO
println(bd++) // 후위 증가 연산자는 println이 실행된 다음에 값을 증가
// 0
println(++bd) // 전위 증가 연산자는 println이 실행되기 전에 값을 증가
// 2
728x90
반응형
'Studying > Kotlin' 카테고리의 다른 글
[Kotlin In Action] 7장. 연산자 오버로딩과 기타 관례(3) - 컬렉션과 범위에 대해 쓸 수 있는 관례 (0) | 2023.06.02 |
---|---|
[Kotlin In Action] 7장. 연산자 오버로딩과 기타 관례(2) - 비교 연산자 오버로딩 (0) | 2023.06.02 |
[Kotlin In Action] 6장. 코틀린 타입 시스템(4) - 컬렉션과 배열 (0) | 2023.06.01 |
[Kotlin In Action] 6장. 코틀린 타입 시스템(3) - 코틀린의 원시 타입 (0) | 2023.05.31 |
[Kotlin In Action] 6장. 코틀린 타입 시스템(2) - 널 가능성[2] (0) | 2023.05.30 |