이건욱 2020. 4. 23. 16:06

Kotlin은 class을 상속하거나 Decorator을 같은 디자인 패턴을 활용 하지 않아도 클래스를 확장시킬수 있는 extensions을 제공합니다.

 

예를 들어 라이브러리 안에 있는 class를 새로운 함수를 추가 하고 싶을 때에 사용할 수가 있습니다.

[예시]

다음은 MutableList<Int>에 swap이라는 함수를 추가한것 입니다.

fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this' corresponds to the list
    this[index1] = this[index2]
    this[index2] = tmp
}

이제 다음과 같이 사용이 가능합니다.

val list = mutableListOf(1, 2, 3)
list.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'list'

당연하게도, 이 함수는 generic으로도 만들수가 있습니다.

fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this' corresponds to the list
    this[index1] = this[index2]
    this[index2] = tmp
}

 

Extensions는 런타임시 정의가 되는 형식이 아닌 정적으로 정의가 되어 집니다.

따라서 다름과 같이 접근을 할수가 있습니다.

open class Shape

class Rectangle: Shape()

fun Shape.getName() = "Shape"

fun Rectangle.getName() = "Rectangle"

fun printClassName(s: Shape) {
    println(s.getName())
    //Shape
}    

printClassName(Rectangle())

만약에 extension 함수가 receiver type에 이미 동일한 이름으로 지정이 되어있다면

기존에 receiver type에 있는 함수가 호출이 됩니다.

class Example {
    fun printFunctionType() { println("Class method") }
}

fun Example.printFunctionType() { println("Extension function") }

Example().printFunctionType()

//Class method

그러나 함수 이름은 같은데 다른 매개변수를 가지고 있다면 아래와 같이 새로 등록한 함수가 호출이 됩니다.

class Example {
    fun printFunctionType() { println("Class method") }
}

fun Example.printFunctionType(i: Int) { println("Extension function") }

Example().printFunctionType(1)

//Extension function

Extension도 마찬가지로 Nullable이 가능합니다 따라서 다음과 같이 작성을 할수가 있습니다.

fun Any?.toString(): String {
    if (this == null) return "null"
    // after the null check, 'this' is autocast to a non-null type, so the toString() below
    // resolves to the member function of the Any class
    return toString()
}

 

Extension properties

함수와 근접하게 Kotlin extension은 properties을 제공합니다.

val <T> List<T>.lastIndex: Int
    get() = size - 1
   
val list = mutableListOf(1,2,3,4,5,6)
println(list.lastIndex)

 

Companin object extensions

만약에 companion object으로 등록을 하고 싶으면 다음과 같이 사용을 할수가 있습니다.

class MyClass {
    companion object { }  // will be called "Companion"
}

fun MyClass.Companion.printCompanion() { println("companion") }

fun main() {
    MyClass.printCompanion()
}

Extension은 packages에서 top level에서 선언을 하거나 아니면 class 안에서 선언을 할수가 있다.

 

top level에서 하는 경우에는 어디에서는 접근을 할수가 있지만 class 에서는 상속을 받거나 해당 class 에서만 사용이 가능합니다.