Extensions ?
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 에서만 사용이 가능합니다.