확장 함수 (Extention Function)

기존에 정의된 클래스에 함수를 추가하여 정의할 수 있는 기능

확장 함수 (Extention Function)

확장 함수


기존에 정의된 클래스에 함수를 추가하여 정의할 수 있는 기능이다.

예를 들어 수정할 수 없는 서드파티 라이브러리의 클래스에 새로운 함수를 작성할 수 있게 되고 일반적인 클래스의 함수인 것처럼 일반적인 방식으로 호출할 수 있게 되는데 이러한 메커니즘을 가진 함수이다.

fun main() {
    "World!".hello()
}

fun String.hello() = println("Hello $this")


// Hello World



확장 함수 형태


확장되는 유형을 참조하는 수신 타입에 . 을 붙여 새로운 함수를 정의할 수 있다.

  • 수신 타입(receiver type)은 확장 대상이 되는 클래스이다.
  • this수신 객체 지정 람다(람다 리시버, Lambda Receiver) 이다.
fun MutableList<Int>.swapIntList(index1: Int, index2: Int) {
    val temp = this[index1]
    this[index1] = this[index2]
    this[index2] = temp
}


제네릭(Generic)을 사용하여 일반화할 수 있다.

fun <T> MutableList<T>.swapList(index1: Int, index2: Int) {
    val temp = this[index1]
    this[index1] = this[index2]
    this[index2] = temp
}



정적 바인딩


확장 함수는 정적 바인딩 되는데 함수 호출 부분에 메모리 주소값을 저장하는 작업이 컴파일 되는 시점에 동작하여 컴파일 이후의 값이 변경되지 않는 것을 의미한다.

멤버 함수가 있는 클래스에 같은 수신 타입, 같은 이름, 같은 인자의 확장 함수가 정의되면 멤버 함수가 실행된다.

fun main() {
    printClassName(Rectangle())
}

fun printClassName(s : Shape) = println(s.getName()) // 확장 함수 호출

fun Shape.getName() = "Shape" // Shape 클래스의 확장 함수
fun Rectangle.getName() = "Rectangle" // Rectangle 클래스의 확장 함수

open class Shape
class Rectangle : Shape() // Rectangle 클래스가 Shape 클래스를 상속 받음


// Shape
  • printClassName()Rectagle 타입의 인스턴스를 전달하였지만 확장 함수는 정적 바인딩 되기 때문에 확장 함수 호출 부분인 s.getName() 에 저장되는 메모리 주소가 이미 컴파일 되는 시점에 결정되어 있다.
  • 확장 함수 호출 부분인 s.getName() 부분에 이미 Shape 클래스의 확장 함수인 getName() 함수가 저장된 메모리 주소가 저장되어 있다.
  • printClassName(Rectangle()) 로 호출하면 s.getName() 부분에 저장된 메모리 주소만을 알고 있기 때문에 이 위치에 있는 코드를 실행하게 된다.

함수의 이름이 같지만 파라미터가 달라 오버로딩(Overloading)이 이루어지는 경우는 다른 함수를 추가하는 것이기 때문에 확장한 함수가 실행된다.

fun main() {
    Test().outputTest(1)
}

fun Test.outputTest(n: Int) = println("Test $n")

class Test {
    fun outputTest() = println("Test")
}


// Test 1
  • 여기서 확장 함수 outputTest(n: Int) 는 멤버 함수인 outputTest() 과 이름이 같지만, 파라미터가 다르기 때문에 확장한 함수가 실행된다.
essential