
코틀린 확장 함수는 기존 클래스 코드를 수정하지 않고도 함수가 붙은 것처럼 호출할 수 있게 해 주는 문법입니다. Java의 static utility 함수보다 읽기 좋은 호출 형태를 만들 수 있습니다.
핵심은 상속으로 타입을 바꾸는 것이 아니라, 특정 receiver 타입에 호출 문법을 붙이는 것입니다. 이 글은 Kotlin 공식 문서의 extension function 규칙을 기준으로 장점과 한계를 함께 정리합니다.

코틀린 확장 함수 기본 구조
확장 함수는 함수 이름 앞에 receiver 타입을 붙여 선언합니다. 그러면 해당 타입의 값에서 멤버 함수처럼 호출할 수 있습니다.
fun String.firstCharOrEmpty(): String {
return if (this.isEmpty()) "" else this[0].toString()
}
val value = "Kotlin".firstCharOrEmpty()여기서 `String`이 receiver 타입이고, 함수 안의 `this`는 호출 대상 문자열을 의미합니다.
클래스에 진짜 멤버가 추가되는 것은 아니다
확장 함수는 호출 문법을 자연스럽게 만들지만, 기존 클래스 자체를 수정하지 않습니다. 그래서 private 멤버에 접근할 수 없고, 실제 dispatch 방식도 멤버 함수와 다릅니다.
class User(val name: String)
fun User.displayName(): String {
return name.trim()
}외부에서 `user.displayName()`처럼 호출할 수 있지만, `displayName`이 User 클래스 내부에 실제로 추가된 것은 아닙니다.
멤버 함수와 이름이 같으면 멤버가 우선된다
Kotlin 공식 문서는 같은 receiver type과 같은 signature의 멤버 함수가 있으면 멤버 함수가 우선한다고 설명합니다. 그래서 확장 함수로 기존 멤버를 몰래 덮어쓸 수 없습니다.
class Printer {
fun print() = "member"
}
fun Printer.print() = "extension"
println(Printer().print()) // member정적으로 결정된다는 점을 조심해야 한다
확장 함수는 runtime type이 아니라 선언된 타입 기준으로 결정됩니다. 다형성처럼 동작한다고 기대하면 헷갈릴 수 있습니다.
open class Shape
class Circle : Shape()
fun Shape.name() = "shape"
fun Circle.name() = "circle"
val shape: Shape = Circle()
println(shape.name()) // shape확장 함수는 상속을 대체하는 다형성 도구가 아니라 호출 문법을 정리하는 도구라고 보는 편이 안전합니다.
nullable receiver도 가능하다
Kotlin은 nullable receiver에도 확장 함수를 만들 수 있습니다. null 자체를 receiver로 받아 안전하게 처리하는 문법을 만들 수 있습니다.
fun String?.orDash(): String {
return this ?: "-"
}
val name: String? = null
println(name.orDash())언제 쓰면 좋을까
- 기존 타입에 작은 변환 함수나 읽기 좋은 도메인 함수를 붙이고 싶을 때
- utility 함수를 `StringUtils.trimName(value)`보다 `value.trimName()`처럼 읽고 싶을 때
- 외부 라이브러리 타입을 상속 없이 프로젝트 문맥에 맞게 다루고 싶을 때
- nullable 처리나 formatting처럼 반복되는 표현을 줄이고 싶을 때
남용하기 쉬운 부분
- 아무 타입에나 많은 확장 함수를 붙여 API 위치를 찾기 어렵게 만든다
- 도메인 로직을 여러 파일의 확장 함수로 흩어 놓는다
- 멤버 함수처럼 보인다는 이유로 실제 소유권을 흐린다
- 다형성이 필요한 문제를 확장 함수로 해결하려 한다
정리
코틀린 확장 함수는 상속 없이 기능을 붙이는 편리한 문법입니다. 다만 실제 멤버가 추가되는 것은 아니며, 정적으로 결정된다는 한계를 함께 기억해야 합니다.
Kotlin 문법 흐름은 코틀린 lateinit lazy 차이, 코틀린 null safety 정리, 코틀린 Nothing 타입이란 무엇인가와 함께 보면 좋습니다. 외부 기준은 Kotlin Docs – Extensions, Kotlin Docs – Extensions are resolved statically, Kotlin Docs – Nullable receiver를 확인했습니다.