반응형
Notice
Recent Posts
Recent Comments
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
- 커스텀상태
- 병럴프로그래밍
- 병렬프로그래밍
- 안드로이드
- 회고
- 코루틴
- 디자인패턴
- 안드로이드강좌
- 테스트
- g 단위테스트
- 스레드
- android
- 글또
- 책
- k8s
- Kotlin
- 코틀린
- ReactiveProgramming
- Coroutine
- Rxjava
- Gradle
- viewmodel
- 안드로이드스튜디오
- 자바
- kotlin강좌
- Compose
- mockito
- 알고리즘
- theming
- 알게되는
Archives
- Today
- Total
선생님, 개발을 잘하고 싶어요.
Kotlin in Action - 2부 7장 - 연산자 오버로딩과 기타 관례 (convention) 본문
2부의 목적
- 코틀린으로 자신의 API를 만드는 법을 배운다.
- 프로그램 안에서 상호작용하는 클래스가 둘 이상이라면 다른 클래스에게 API를 제공하는 클래스가 적어도 하나 이상이므로, 라이브러리 개발자가 아니더라도 중요한 내용이다.
다루는 것
- 특정 함수 이름과 연관된 관례 (convention)
- 위임 프로퍼티
관례
- operator 키워드를 붙임으로써 어떤 함수가 관례를 따르는 함수임을 명확히 한다.
- operator 없이 관례에서 사용하는 함수 이름을 쓴다면 컴파일러가 알려준다.
- 멤버 함수 뿐 아니라 확장 함수로도 operator 연산자를 정의할 수 있다.
산술 연산자 오버로딩
- 프로그래머가 직접 연산자를 만들어 사용할 수 없고 언어에서 미리 정해둔 연산자만 오버로딩할 수 있다.
- 클래스에서 정의해야하는 이름이 연산자별로 정해져 있다.
- 연산자 우선순위또한 표준 숫자 타입에 대한 연산자 우선순위와 같다.
- 종류
- 이항 산술 연산자 (a + b)
- plus 함수는 새로운 객체를 반환한다
- 복합 대입 연산자 (a += b)
- plusAssign 함수는 기존 객체의 내부 상태를 변경시킨다.
- 단항 연산자 (+a)
- unaryPlus 함수는 파라미터가 없다.
- plus 연산과 plusAssign을 동시에 정의하지 마라.
- 변경이 불가능하다면 plus와 같이 새로운 값을 반환하는 연산만 추가하고, 변경 가능한 클래스를 설계한다면 plusAssign 과 같은 연산을 제공하자.
- 이항 산술 연산자 (a + b)
비교 연산자 오버로딩
- 동등성 연산자: equals (==)
- Any에 정의된 equals는 항상 확장함수보다 우선순위가 높으니 확장함수로 동등성 연산자를 정의할 수 없다.
- 순서 연산자: compareTo (>, <, >=, <=)
인덱스로 원소에 접근: get, set
mutableMap[key] = newValue // 와 같은 코드가 동작한다.
operator fun Point.get(index: Int): Int {
..
}
- 이렇게 각괄호([]) 안에 인자를 기준으로 원소를 받아오는 함수를 만들고 싶다면 get이라는 메서드를 만들고 operator 변경자를 붙이기만 하면 된다.
- 파라미터가 Int가 아니여도 괜찮다.
- 여러 파라미터를 사용하는 get을 정의할 수도 있다.
- 다양한 파라미터 타입에 대해 오버로딩한 get을 제공할 수 도 있다.
in 관례 (contains)
- 컬렉션이 지원하는 in은 contains에 해당한다.
rangeTo 관례 (..)
- 범위를 만들려면 .. 구문을 사용해야한다.
- .. 연산자는 rangeTo 함수를 간략하게 표현하는 방법이다.
- 어떤 클래스가 Comparable 인터페이스를 구현하면 rangeTo를 정의할 필요가 없다.
for 루프를 위한 iterator 관례
for (x in list) { … }
- 이런 문장은 list.iterator() 호출해서 이터레이터를 얻은 이후, hasNext, next 호출을 반복하는 식으로 변환된다.
구조 분해 선언과 component 함수
- destructing declaration, 복합적인 값을 분해해서 여러 다른 변수를 한꺼번에 초기화할 수 있다.
- data 클래스는 주 생성자에 들어있는 프로퍼티에 대해서는 컴파일러가 자동적으로 componentN 함수를 만들어준다.
- 배열과 컬렉션도 5개 요소 까지는 componentN 함수가 있다. 따라서 크기가 정해진 컬렉션을 다루는 경우 구조 분해가 유용하다.
- 본문 내 선언 문 뿐 아니라 변수 선언이 들어갈 수 있는 장소라면 어디든 구조 분해 선언을 사용할 수 있다.
val map: Map<String, String>
for ((key, value) in map) { // 루프 변수에 구조 분해 선언 사용
...
}
// 이런 확장 함수 제공하기 때문에 가능
operator fun Map.Entry.component1()
operator fun Map.Entry.component2()
프로퍼티 접근자 로직 재활용: 위임 프로퍼티 (delegated property)
- 관례에 의존하는 특성 중 독특하면서 강력한 기능인 위임 프로퍼티
- 자신의 값을 필드가 아니라 데이터베이스 테이블, 브라우저 세션, 맵 등에 저장하고 싶은가?
- 위임: 도우미 객체에게 그 작업을 처리하게 맡기는 디자인 패턴
- 위임 객체(delegate): 작업을 처리하는 도우미 객체
class Foo {
var p: Type by Delegate()
}
- p 프로퍼티는 접근자 로직을 다른 객체에 위임한다.
- by 키워드 뒤에 식을 계산한 결과인 Delegate 객체에게 위임에 쓰일 객체를 얻는다.
- p는 내부 필드를 유지하지 않고, 그 프로퍼티의 게터나 세터는 delegate의 getValue, setValue를 호출하게 됨
class Delegate(
val propValue: Int
) {
operator fun getValue(p: Person, prop: KProperty<*>): Int = propValue
operator fun setValue(p: Person, prop: KProperty<*>, newValue: Int) {
...
}
}
- 코틀린은 프로퍼티를 표현하는 객체로 KProperty 타입을 활용
- 컴파일러가 대충 다음과 같은 일을 한다
- by 키워드 뒤의 식으로 초기화 되는 객체를 감춰진 프로퍼티에 저장 <delegate>
- 프로퍼티를 표현하기 위해 KProperty 타입의 객체 제공
// 이 프로퍼티 위임 코드는 class C { var prop: Type by MyDelegate() } // 다음과 같이 컴파일 된다. class C { private val <delegate> = MyDelegate() var prop: Type get() = <delegate>.getValue(this, <property>) set(value: Type) = <delegate>.setValue(this, <property>, value) }
'일상 > 책 리뷰' 카테고리의 다른 글
Kotlin in Action - 2부 9장 - 제네릭스 (0) | 2022.05.29 |
---|---|
Kotlin in Action - 2부 8장 - 고차 함수: 파라미터와 반환 값으로 람다 사용 (0) | 2022.05.28 |
Kotlin in Action - 1부 6장 - 코틀린 타입 시스템 (0) | 2022.05.23 |
Kotlin in Action - 1부 5장 - 람다로 프로그래밍 (0) | 2022.05.22 |
Kotlin in Action - 1부 4장 - 클래스, 객체, 인터페이스 (0) | 2022.05.21 |
Comments