티스토리 뷰

728x90

 

연산자 오버로딩

  • - +, -, *, / 등 코틀린 내장 연산자에 대해 새로운 의미를 부여할 수 있게 해준다.
operator fun String.times(n: Int) = repeat(n)

fun main() {
    println("abc" * 3)      // abcabcabc
    println("abc".times(3)) // abcabcabc
}
 
  • 연산자를 구현하기 위해 함수 앞에 operator 키워드를 붙인다.

 

 

      1. 단항 연산

enum class Color {
    BLACK, WHITE, BLUE, YELLOW;
     
    operator fun not() = when(this) {
        BLACK -> WHITE
        WHITE -> BLACK
        BLUE -> YELLOW
        YELLOW -> BLUE
    }
}

fun main() {
    println(!Color.BLUE) // YELLOW
}
 
의미
+e e.unaryPlus()
-e e.unaryMinus()
!e e.not()

 

 

 

      2. 이항 연산

  • 왼쪽 피연산자를 receiver, 오른쪽 피연산자를 인자로 받는다.
  • 파라미터가 하나인 멤버/확장 함수여야 한다.
class A(val str: String, val i: Int) {
    override fun toString() = "$str $i"
}

operator fun A.plus(other: A): A {
    val ret = A(this.str + other.str, this.i + other.i)
    return ret
}

fun main() {
    println(A("Hello", 10) + A("World", 4)) // HelloWorld 14
}
 
의미
a + b a.plus(b)
a - b a.minus(b)
a .. b a.rangeTo(b)
a in b b.contains(a)

 

 

 

      3. 중위 연산

public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)

fun main() {
    val pair1 = 1 to 2  // 중위 연산 사용
    val pair2 = 1.to(2) // 일반적인 호출
}
  • 중위 연산을 선언하기 위해 함수 앞에 infix를 붙여야 한다.

 

 

 

      4. 복합 대입 연산

  • 커스텀 복합 대입 함수가 있으면 그 함수를 사용하고, 없는 경우 이항 연산자와 대입 연산자로 해석한다.
  • a += b 인 경우 plusAssign이 있으면 a.plusAssign(b), 없으면 a = a.plus(b)
  • MutableList에 +=, -=를 사용하면 List에 원소가 추가되거나 삭제된다.
  • 이는 대입 복합 연산인 plusAssign(), minusAssign()이 정의되어 있기 때문이다.

 

 

 

      5. invoke(): 값을 함수처럼 사용

operator fun <K, V> Map<K, V>.invoke(key: K) = get(key)

fun main() {
    val map = mapOf("I" to 1, "V" to 5, "X" to 10)
     
    // invoke()를 통해 값을 함수처럼 사용
    println(map("V")) // 5
    println(map("L")) // null
}
  • 함수 타입의 값은 자동으로 invoke()가 생성된다.
  • 임의의 타입에 대해 invoke()를 생성할 수 있다.

 

class A private constructor() {
    companion object {
        fun make() = A()
    }
}

operator fun A.Companion.invoke() = make()

fun main() {
    val a = A() // invoke() -> make() -> private constructor
}
 
  • invoke()를 통해 동반 객체를 팩토리로 만들 수 있다.

 

 

      6. get(), set()

  • List에서 []를 사용해 접근/변경 가능한 것도 operator fun get(), set()이 정의되어 있기 때문이다.
 
fun main() {
    val list = mutableListOf(1, 2)
     
    println(list[0])    // list.get(0)과 동일
    list[1] = 3         // list.set(1, 3)과 동일
}

 

 

      7. 구조 분해 (Destructuring)

class Person(val name: String, val age: Int) {
    operator fun component1() = name
    operator fun component2() = age
}

fun main() {
    val (name, age) = Person("John", 20)
    println("$name $age") // John 20
}
  • 클래스의 멤버 함수나 확장 함수로 componentN을 정의하면 구조 분해를 사용할 수 있다.
  • 구조 분해를 할 수 있는 data class, map, list, array에서도 componentN()이 정의되어 있다.

 

 

 

728x90
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/08   »
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
글 보관함