일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- r
- builderPattern
- a
- Design Pattern
- PrototypePattern
- 싱글톤
- F
- 옵저버 패턴
- Abstract Factory
- factory method
- 디자인패턴
- 추상 팩토리
- 프로토타입 패턴
- ㅓ
- 추상팩토리패턴
- designPattern
- Kotlin
- Functional Programming
- Observer Pattern
- 디자인패턴 #
- ㅋㅁ
- Singleton
- 코틀린
- 빌터패턴
- 함수형프로그래밍
- El
- 팩토리 메소드
- Today
- Total
오늘도 더 나은 코드를 작성하였습니까?
연산자 오버로딩과 기타 관례(컬렉션과 범위에 대해 쓸 수 있는 관례) 본문
컬렉션을 다룰 때 가장 많이 쓰는 연산은 인덱스를 사용해 원소를 읽거나 쓰는 연산과 어떤 값이 컬렉션에 포함되어 있는지 확인하는 연산이다.
인덱스로 원소에 접근: get set
코틀린에서는 인덱스 연산자도 관례를 따른다.
인덱스 연산자를 사용해 원소를 읽는 연산은 get으로 변환되고 원소를 쓰는 연산은 set으로 변환된다.
data class Point(val x: Int, val y: Int)
operator fun Point.get(index: Int): Int{
return when(index){
0 -> x
1 -> y
else ->
throw IndexOutOfBoundsException("Invalid coordinate $index")
}
}
fun main() {
val p = Point(10,20)
println(p[0])
println(p[1])
}
p [0] ====> p.get(0)으로 변환된다.
get 메서드의 파라미터로 어떤 타입을 사용해된다. 또한 여러 개의 파라미터를 사용하는 get을 정의해도 된다.
다양한 키 타입을 지원해야 한다면 get메서드를 여럿 오버 로딩하면 된다.
data class MutablePoint(var x:Int, var y:Int)
operator fun MutablePoint.set(index: Int, value: Int){
when(index){
0 -> x = value
1 -> y = value
else -> throw IndexOutOfBoundsException("Invalid coordinate $index")
}
}
fun main() {
val p = MutablePoint(10,20)
p[0] = 20
p[1] = 30
println(p)
}
set의 경우 받는 마지막 파라미터 값은 대입문의 우항에 들어가고 나머지 파라미터 값은 [ ] 인덱스 연산자로 들어간다.
p [0] = 20 ====> p.set(0, 20)
p [1] = 30 ====> p.set(1, 30)
in (포함) 관례
컬렉션이 지원하는 다른 연산자로는 in이 있다.
in은 컬렉션에 객체 들어있는지 확인한다. 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() {
val rectangle = Rectangle(Point(10, 20),Point(50,50))
println(Point(20,30) in rectangle)
println(Point(5,5) in rectangle)
}
until 함수를 사용하여 열린 범위를 만든다.(참고 10.. 20은 10과 20을 포함하지만 10 until 20 은 20은 포함하지 않는다)
a in c ====> c. contains( a )
rangeTo(범위) 관례
범위를 만들려면 .. 구문을 사용한다.
.. 연산자는 rangeTo에 대응한다.
rangeTo 함수는 범위를 반환한다. 이 연산자를 어떤 클래스에도 정의할 수 있다.
하지만 클래스가 comparable 인터페이스를 구현한다면 rangeTo를 정의할 필요가 없다.
코틀린 표준 라이브러리를 통해 비교 가능한 객체로 이뤄진 범위를 쉽게 생성할 수 있다.
코틀린 표준 라이브러리에는 모든 comparable 객체에 대해 적용 가능한 rangeTo함수가 들어있다.
operator fun <T: Comparable <T>> T.rangeTo(that: T): ClosedRange <T>
예제
fun main() {
val now = LocalDate.now()
val vacation = now..now.plusDays(10)
println(now.plusWeeks(1) in vacation)
val n = 9
println(0..(n+1)) // 산술연산자보다 우선순위가 낮다
(0..n).forEach { println(it) } // 우선순위가 낮아서 메서드 호출시 괄호를 써주는게 좋다.
}
now.. now.plusDays ====> now.rangeTo(now.plusDays(10))
for 루프를 위한 iterator 관례
코틀린의 for 루프는 범위 검사와 똑같이 in 연산자를 사용한다.
하지만 이 경우의 in의 의미는 다르다.
for (x in list) {...}는 list.iterator() 객체를 얻은 후에 hasNext와 next호출을 반복하는 식으로 변환된다.
String의 상위 클래스인 CharSequence에 대한 iterator 확장 함수를 제공한다.
operator fun CharSequence.iterator(): CharIterator
예제
operator fun ClosedRange<LocalDate>.iterator(): Iterator<LocalDate> =
object : Iterator<LocalDate> {
var current = start
override fun hasNext(): Boolean =
current <= endInclusive
override fun next(): LocalDate = current.apply {
current = plusDays(1)
}
}
fun main() {
val newYear = LocalDate.ofYearDay(2020, 1)
val daysOff = newYear.minusDays(2)..newYear
for (day in daysOff)
println(day)
}
rangeTo 라이브러리 함수는 ClosedRange 인스턴스를 반환한다.
ClosedRange <LocalDate>에 대한 확장 함수에 iterator를 정의했기 때문에 LocalDate의 객체 범위를 for 루프에서 사용 가능한 것이다.
'Kotlin in Action > 코틀린 답게 사용하기' 카테고리의 다른 글
연산자 오버로딩과 기타 관례(위임 프로퍼티 기타) (0) | 2020.08.25 |
---|---|
연산자 오버로딩과 기타 관례(프로퍼티 접근자 로직 재활용: 위임 프로퍼티) (0) | 2020.08.25 |
연산자 오버로딩과 기타 관례(구조 분해 선언과 component 함수) (0) | 2020.08.24 |
연산자 오버로딩과 기타 관례(비교 연산자 오버로딩) (0) | 2020.08.22 |
연산자 오버로딩과 기타 관례(산술 연산자 오버로딩) (0) | 2020.08.22 |