확장 함수와 확장 프로퍼티

2018, Jun 22    

코틀린에는 기존에 정의 된 클래스를 수정하지 않고 마치 그 클래스의 멤버 함수인 것처럼 사용할 수 있는 함수를 정의 할 수 있다. 이와 같은 함수를 확장 함수라고 한다.

확장함수extension function는 이미 정의된 클래스에 새로운 기능을 추가하여 사용하고자 할때 기존 클래스를 수정하지 않고도 필요한 기능을 추가할 수 있다는 장점이 있다. 특히 자바 프로젝트와 통합하고자 할때 기존 자바 API를 수정하지 않아도 된다는 점에서 큰 장점인 듯 하다.

아래는 String객체를 확장한 함수이다.

fun String.lastChr(): Char = this.get(this.length - 1)

확장함수 구조를 확인해 보자.

exfunction

실행은 아래와 같이 하며, 문자열의 마지막 캐틱터값을 반환하는 것을 알 수 있다.

>>> println("kotlin".lastChr())
n

여기서 수신객체는 “kotlin”이며, 수신객체 타입은 “String”이다.
함수 ‘lastChr’는 클래스 내의 일반 메서드에서와 마찬가지로 this를 사용할 때와 마찬가지로,
똑같이 사용 할 수 있다. 즉, 여기서 this는 String객체인 “kotlin” 참조 객체를 의미한다.
따라서 this.get()과 this.length는 String 객체인 “kotlin”의 멤버 함수와 변수이다.

String의 멤버인 get(), length

exfunction

  • 위 확장함수 식에서 this는 생략 가능 하다.
    fun String.lastChr(): Char = this.get(length - 1)
    
  • 이렇게 확장 함수는 마치 기존 객체의 멤버 함수 인 것처럼 this와 다른 멤버필드 및 메소드에 접근가능하지만 이것이 캡슐화를 해치지는 않는다.

  • 클래스 안에서 정의한 메소드와 달리 확장 함수 안에서는 클래스 내부에서만 사용할 수 있는 private멤버나 protected멤버를 사용할 수 없다.

  • 확장 함수는 프로젝트 안의 모든 소스코드에서 사용할 수 있는 것은 아니고, 다른 파일(.kt)에서 사용하기 위해서는 그 함수를 import해야만한다.

  • 확장 함수는 오버라이드 할 수 없다. 확장 함수는 클래스의 일부가 아니라 클래스 밖에 선언 되기 때문이다.
open class View {
    open fun click() = println("View clicked")
}

class Button: View() {
    override fun click() = println("Button clicked")
}

fun View.showOff() = println("I'm a view!")
fun Button.showOff() = println("I'm a Button!")

>>> val view:View = Button()
>>> view.showOff()
I'm a view!

확장 프로퍼티

   이런 확장 함수를 이용하여 확장 프로퍼티를 만들 수 있다. 바로 멤버변수의 accessor를 확장함수로 커스텀 하는 방법인데, 위에서 만난 확장 함수를 확장 프로퍼티로 변경하는 코드를 살펴 보자.

fun String.lastChr(): Char = this.get(this.length - 1)

//getter함수를 확장함수로 커스텀 하여 확장프로퍼티로 만듦
val String.lastChr : String
  get() = get(length-1)

이런식으로 setter를 커스텀하여서도 가능하다.

var StringBuilder.lastChar: Char
  get() = get(length-1)
  set(value: Char) {
      this.setCharAt(length - 1, value)
  }

>>> println("Kotlin".lastChr)
n
>>> val sb = StringBuilder("Kotlin?")
>>> sb.lastChr = '!'
>>> println(sb)
Kotlin!