Recent Posts
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- PersistenceContext
- preemption #
- 자원부족
- table not found
- 헥사고날아키텍처 #육각형아키텍처 #유스케이스
- 겨울 부산
- Spring Batch
- k8s #kubernetes #쿠버네티스
- pytest
- 깡돼후
- python
- tolerated
- PytestPluginManager
- JanusWebRTCGateway
- 달인막창
- 개성국밥
- 코루틴 컨텍스트
- 오블완
- taint
- JanusWebRTC
- vfr video
- JanusGateway
- terminal
- VARCHAR (1)
- JanusWebRTCServer
- mp4fpsmod
- Value too long for column
- kotlin
- 티스토리챌린지
- 코루틴 빌더
Archives
너와 나의 스토리
[Kotlin] 연산자 오버로딩 본문
반응형
연산자 오버로딩
- 자바에는 표준 라이브러리와 밀접하게 연관된 언어 기능이 몇 가지 있다.
- 예를 들어 for ... in 루프에 java.lang.Iterable을 구현한 객체를 사용할 수 있다.
- 코틀린에서는 이러한 언어 기능이 어떤 타입(클래스)과 연관되기보다는 특정 함수 이름과 연관된다.
- 예를 들어 어떤 클래스 안에 plus라는 이름의 특별한 메서드를 정의하면 그 클래스의 인스턴스에 대해 + 연산자를 사용할 수 있다.
- 이런 식으로 어떤 언어 기능과 미리 정해진 이름의 함수를 연결해주는 기법을 코틀린에서는 관례(convention)라고 부른다.
예: Point 클래스
data class Point(val x: Int, val y: Int)
산술 연산자 오버로딩
이항 산술 연산 오버로딩
- Point에서 지원하고픈 첫 번째 연산은 두 점을 더하는 연산이다. 이 연산은 두 점의 X 좌표와 Y 좌표를 각각 더한다.
-
data class Point(val x: Int, val y: Int) { operator fun plus(other: Point): Point { return Point(x + other.x, y + other.y) } } fun main(args: Array<String>) { val p1 = Point(10, 20) val p2 = Point(30, 40) println(p1 + p2) // output: Point(x=40, y=60) }
- plus 함수 앞에 operator 키워드를 붙여야 한다.
- operator 키워드를 붙임으로써 어떤 함수가 관례를 따르는 함수임을 명확히 할 수 있다.
-
- 연산자를 멤버 함수로 만드는 대신 확장 함수로 정의할 수도 있다.
-
data class Point(val x: Int, val y: Int) operator fun Point.plus(other: Point): Point { return Point(x + other.x, y + other.y) }
-
코틀린은 교환 법칙을 지원하지 않는다.
operator fun Point.times(scale: Double): Point {
return Point(x * scale, y * scale)
}
fun main(args: Array<String>) {
val p1 = Point(10.0, 20.0)
println(p1*0.1)
// println(0.1*p1) <- error
}
- (0.1*p1)을 하기 위해서는 다음과 같이 연산자 함수를 추가로 작성해줘야 한다.
operator fun Double.times(p: Point): Point {
return Point(toDouble() * p.x, toDouble()*p.y)
}
오버로딩 가능한 이항 산술 연산자
식 | 함수 이름 |
a + b | times |
a / b | div |
a % b | mod (1.1부터 rem) |
a + b | plus |
a - b | minus |
컬렉션과 범위에 대해 쓸 수 있는 관례
인덱스로 원소에 접근: get과 set 연산자
- get 관례
- Point의 x좌표는 인덱스 0, y 좌표는 인덱스 1로 생각하고 접근한다.
data class Point(var x: Int, var y: Int)
operator fun Point.get(index: Int): Int {
return when (index) {
0 -> x
1 -> y
else -> throw IndexOutOfBoundsException("Invalid coordinate $index")
}
}
fun main(args: Array<String>) {
val p = Point(10,20)
println(p[0]) // output: 10 (x 좌표)
println(p[1]) // output: 20 (y 좌표)
}
- set 관례
operator fun Point.set(index: Int, value: Int){
when(index){
0 -> x = value
1 -> y = value
else -> throw IndexOutOfBoundsException("Invalid coordinate $index")
}
}
fun main(args: Array<String>) {
val p = Point(10,20)
p[1]=30
println(p[0]) // output: 10 (x 좌표)
println(p[1]) // output: 20 (y 좌표)
}
in 관례
- in은 객체가 컬렉션에 들어있는지 검사한다.
- a in x unitl y
- a가 [x,y] 범위에 속하는가? True or False
- a in x unitl y
- 이러한 in 연산자와 대응하는 함수는 contains다.
data class Rectangle(val upperLeft: Point, val lowerRight: Point)
operator fun Rectangle.contains(p: Point): Boolean {
return p.x in upperLeft.x until lowerRight.x &&
p.y in upperLeft.y until lowerRight.y
}
fun main(args: Array<String>) {
val rect = Rectangle(Point(10, 20), Point(50, 50))
val p1 = Point(10, 20)
val p2 = Point(5, 5)
println(p1 in rect) // output: true
println(p2 in rect) // output: false
}
rangeTo 관례
- .. 연산자는 범위를 만들 때 사용된다.
- 이는 rangeTo 함수와 대응된다.
val now = LocalDate.now()
val vacation = now..now.plusDays(10)
val vacation2 = now.rangeTo(now.plusDays(10))
println(now.plusWeeks(1) in vacation) // output: true
println(now.plusWeeks(1) in vacation2) // output: true
for 루프를 위한 iterator 관례
- for (x in list) {...}는 list.iterator()를 호출해서 이터레이터를 얻은 다음, 그 이터레이터에 대해 hasNext와 next 호출을 반복하는 식으로 변환된다.
- 코틀린에서는 이 또한 iterator 메서드를 확장 함수로 정의할 수 있다.
- 예: 날짜 범위에 대한 이터레이터 구현
-
operator fun ClosedRange<LocalDate>.iterator(): Iterator<LocalDate> = object : Iterator<LocalDate> { var current = start override fun hasNext() = current <= endInclusive override fun next() = current.apply { current = plusDays(1) } } fun main(args: Array<String>) { val newYear = LocalDate.ofYearDay(2017, 1) val daysOff = newYear.minusDays(1)..newYear for (dayOff in daysOff) { println(dayOff) } /* output: 2016-12-31 2017-01-01 * */ }
-
구조 분해 선언(destructuring declaration)과 component 함수
- 구조 분해를 사용하면 복합적인 값을 분해해서 여러 다른 변수를 한꺼번에 초기화할 수 있다.
- 구조 분해 사용 방법:
-
val p = Point(10, 20) val (x, y) = p println(x) // output: 10 println(y) // output: 20
-
- 구조 분해 선언은 .componentN으로 변환된다.
- 즉, x의 경우 p.component1(), y의 경우 p.component2() 함수를 호출한 것이다.
- 맵의 원소에 대해 이터레이션
-
fun printEntries(map: Map<String, String>) { for ((key, value) in map) { println("$key -> $value") } }
-
출처:
- [Kotlin IN ACTION]
반응형
'Programming Language > Kotlin' 카테고리의 다른 글
[Kotlin] 안전하게 프로그래밍 하기 (0) | 2021.08.23 |
---|---|
[Kotlin] 위임 프로퍼티(delegated property) / by lazy()를 사용한 초기화 지연 / lateinit (0) | 2021.06.29 |
[Kotlin] 컬렉션과 배열 (0) | 2021.06.18 |
[Kotlin] 코틀린의 원시 타입 (1) | 2021.06.18 |
[Kotlin] 코틀린 타입 시스템 - ? / !! /.? / as? / let 함수 / lateinit (0) | 2021.06.17 |
Comments