확장 함수/extension functions는 상속이나 클래스 자체를 변경하지 않고도 기존 클래스에 새로운 함수를 추가할 수 있는 메커니즘입니다.
예를 들어, String 클래스에 문자열을 뒤집는 함수를 추가해보겠습니다:
fun String.reverse(): String { return this.reversed() } println("abc".reverse()) // "cba"
확장 함수는 실제로 클래스를 수정하지 않으며, 단순한 문법적 설탕으로 컴파일됩니다: 이들은 객체의 인스턴스를 첫 번째 매개변수로 받는 정적 메서드로 컴파일됩니다.
장점: 간결함, 가독성, 코드 확장성. 유틸리티 함수로 컬렉션, 문자열 등에 잘 어울립니다.
주요 주의 사항:
확장 함수를 사용하여 클래스에 상태를 저장하는 새로운 변수를(property)을 추가할 수 있을까요?
답변: 아닙니다. 확장 프로퍼티는 항상 계산되는 속성(getter/setter)일 뿐이며, 필드가 아닙니다. 상태를 저장할 수 없고, 실행 시 계산만 가능합니다.
val String.secondChar: Char get() = this[1] // 계산만, 저장되지 않음!
이야기
데이터 검증 프로젝트에서 개발자가 모델 클래스에 확장 프로퍼티를 추가했지만, 나중에 해당 값이 항상 계산되고 기억되지 않음을 알아차려 여러 번 호출 시 로직이 잘못 작동했습니다.
이야기
큰 애플리케이션에서 확장 함수가 클래스 메서드와 동일한 이름으로 명명되어 혼란을 초래했습니다: 클래스 메서드가 항상 우선했기에 확장 함수는 호출되지 않았으며, "보이지 않는" 코드를 디버깅하는 데 하루가 소요되었습니다.
이야기
한 라이브러리에서 확장 함수를 클래스의 private 필드에 사용했으나, 이들이 private에 접근할 권한이 없음을 알게 되어 모델 아키텍처를 리팩토링해야 했습니다.