이 포스팅은 Kotlin in Action, 드미트리 제메로프 & 스베트라나 이사코바, 에이콘출판사(2017)을 읽고 개인 학습용으로 정리한 글입니다.
관례(convention): 언어 기능과 미리 정해진 이름의 함수를 연결해주는 기법
기존 자바 클래스에 대해 확장 함수 구현하면서 관례에 따라 이름 붙이면
기존 자바 코드를 바꾸지 않아도 새로운 기능 쉽게 부여 가능
operator 키워드: 어떤 함수가 관례를 따르는 함수임을 명시
-> 연산자를 오버로딩하는 함수 앞에는 꼭 operator 있어야
operator 함수도 오버로딩 가능
-> 이름은 같지만 파라미터 타입 서로 다른 연산자 함수 여러개 가능
operator가 없는데 실수로 관례에서 사용하는 함수 이름을 쓰고 우연히 그 이름에 해당하는 기능을 사용하는 경우 operator modifier is required... 오류 발생
연산자를 멤버 함수로 만드는 대신 확장 함수로 정의할 수도 있다
-> 외부 클래스에 대한 연산자를 정의할 때는 관례를 따르는 이름의 확장 함수로 구현하는 게 일반적인 패턴
코틀린에서는 프로그래머가 직접 연산자를 만들어 사용 X
언어에서 미리 정해둔 연산자만 오버로딩 가능
-> 관례에 따르기 위해 클래스에 정의해야 하는 이름 연산자별로 정해져 있음
오버로딩 가능한 이항 산술 연산자: times, div, mod(rem), plus, minus
연산자 우선순위 언제나 표준 숫자 타입에 대한 연산자 우선순위와 같음
연산자 정의할 때 두 피연산자 같은 타입일 필요 X
연산자 함수의 반환 타입 꼭 두 피연산자 중 하나와 일치할 필요 X
복합 대입 연산자(compound assignment)
plus와 같은 연산자를 오버로딩하면
-> 코틀린은 + 연산자 뿐 아니라 그와 연관된 += 연산자도 자동으로 함께 지원
-> 변수가 변경 가능한 경우에만 += 사용 가능
경우에 따라 += 연산이 객체에 대한 참조를 바꾸기 보다 원래 객체의 내부 상태를 변경하게 만들고 싶을 때
-> 반환 타입 Unit인 plusAssign 함수 정의
이론적으로 +=를 plus와 plusAssign 양쪽으로 컴파일 가능
-> 어떤 클래스가 이 두 함수 모두 정의 & 둘다 사용 가능한 경우 컴파일러는 오류 보고
-> plus와 plusAssign 동시에 정의 X
코틀린 표준 라이브러리는 컬렉션에 대해 두 가지 접근 방법 함께 제공
오버로딩 가능한 단항 산술 연산자: unaryPlus, unaryMinus, not, inc, dec
inc, dec 함수를 정의해 증가/감소 연산자를 오버로딩하는 경우
-> 컴파일러는 일반적인 값에 대한 전위, 후위 증가/감소 연산자와 같은 의미 제공
코틀린 == 연산자: equals 메서드 호출로 컴파일
a==b
-> a?.equals(b) ?: (b==null)
== 와 != 내부에서 인자가 널인지 검사
-> 다른 연산과 달리 널이 될 수 있는 값에도 적용 가능
class Point(val x: Int, val y: Int){
override fun equals(obj:Any?):Boolean{
if(obj === this) return true
if (obj !is Point) return false
return obj.x == x && obj.y == y
}
}
fun main() {
println(Point(10, 20) == Point(10, 20))
println(Point(10, 20) == Point(1, 2))
println(Point(10, 20) == null)
}
식별자 비교 연산자(===): 자신의 두 피연산자가 서로 같은 객체를 가리키는지 비교
-> 자바의 == 연산자와 같음
-> === 연산자를 오버로딩할 수 X
Any에 정의된 메서드이므로 다른 연산자 오버로딩 관례와 달리 override 사용
-> Any의 equals에 operator가 붙어있음
Any에서 상속받은 equals가 확장 함수보다 우선순위 높음
-> equals 확장 함수로 정의할 수 X
자바에서 정렬이나 최댓값, 최솟값 등을 비교해야하는 알고리즘: Comparable 인터페이스 구현해야
-> Comparable에 들어있는 compareTo 메서드: 한 객체와 다른 객체의 크기 비교해 정수로 나타냄
코틀린은 Comparable 인터페이스 안에 있는 compareTo 메서드를 호출하는 관례 제공
-> 비교 연산자는 compareTo로 컴파일됨
a>=b
-> **a.compareTo(b) >= 0
compareValuesBy: 두 객체의 대소를 알려주는 0이 아닌 값이 나올 때까지 인자로 받은 함수를 차례로 호출해 두 값 비교
-> 모든 함수 0 반환하면 0 반환
-> ⚡각 비교 함수는 람다나 프로퍼티/메서드 참조일 수 있다
Comparable 인터페이스를 구현하는 모든 자바 클래스
-> 코틀린에서는 연산자 구문으로 비교 가능
-> 확장 메서드 만들 필요 X
class Point(val x: Int, val y: Int)
fun main() {
operator fun Point.get(index:Int):Int{
return when(index){
0 -> x
1 -> y
else -> throw IndexOutOfBoundsException("Invalid coordinate ${index}")
}
}
val point = Point(10, 20)
println("${point[0]} ${point[1]}")
}
.. 연산자는 rangeTo 함수를 간략하게 표현하는 방법
-> rangeTo 함수는 범위 반환
start .. end
-> start.rangeTo(end)
코틀린 표준 라이브러리에는 모든 Comparable 객체에 대해 적용 가능한 rangeTo 함수 존재
-> 어떤 클래스가 Comparable 인터페이스를 구현하면 rangeTo 구현할 필요 X
어떤 원소가 그 범위 안에 들어있는지 in을 통해 검사 가능
범위 연산자는 우선순위 낮음
-> 범위의 메서드를 호출하려면 범위 괄호로 둘러싸야