[코틀린 기초] 코틀린 확장함수
확장함수란
코틀린에서는 기존 클래스를 상속하거나 데코레이터 패턴 같은 디자인 패턴을 활용하지 않고도 클래스의 사용 목적을 확장할 수 있도록 기능을 제공합니다.
예를 들어, String 클래스를 예로 String 인스턴스의 맨 첫번째 요소를 가져오는 함수를 만들어두고 표준라이브러리에 추가하는 효과처럼 보이고 싶다면
fun String.getFirstWord() = this[0]
fun main() {
val str = "str";
println(str.getFirstWord())
}
// s
이런식으로 마치 String 클래스에 이어서 getFirstWord라는 함수를 추가해두고 필요할 때 호출해서 사용할 수 있다. main 함수에서는 마치 이미 String 클래스에 해당 함수가 들어있던 것처럼 보인다.
this 키워드는 String 클래스 타입의 인스턴스를 나타내고 main 함수 내에서는 "str"이라는 문자열을 지칭하게 된다.
그런데 코틀린 컴파일러는 어떻게 이런걸 제공할 수 있을까?
인텔리제이의 kotlin bytecode 기능을 이용해서 해당 코드를 디컴파일 해보자
public final class _5_ExtensionKt {
public static final char getFirstWord(@NotNull String $this$getFirstWord) {
Intrinsics.checkNotNullParameter($this$getFirstWord, "$this$getFirstWord");
return $this$getFirstWord.charAt(0);
}
public static final void main() {
String str = "str";
char var1 = getFirstWord(str);
System.out.println(var1);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
자바로 코드를 변경해보니 psvm 메인 메소드가 별도로 존재하고 코틀린의 main 함수를 호출하고 있다. 그런데 getFirstWord 메소드를 보면 내용이 내가 구현했던 this[0] 과 구현부가 똑같다.
결과적으로 charAt(0) 이라는 구문을 통해 첫번째 문자열을 가져온다.
그렇다. 코틀린은 컴파일하게되면 이렇게 내부적으로는 static 메소드를 하나 생성해두고 마치 표준라이브러리를 호출하는 것처럼 꾸며낸 것이다.
그렇다면 외부 파일에서는 해당 코드를 실행할 수 있을까???
실행가능하다. 실행 가능한 이유도 자바코드로 살펴보자
public final class _5_Extension_exKt {
public static final void main() {
String str = "str";
char var1 = _5_ExtensionKt.getFirstWord(str);
System.out.println(var1);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
getFirstWord 메소드가 선언된 코틀린파일인 _5_ExtensionKt (위에서 컴파일된 클래스임) 에서 static으로 호출한다.
결과적으로 확장함수는 사실
선언한 클래스파일의 static 메소드일 뿐이다.
클래스의 static 메소드라면 만약 동일한 메소드 시그니처를 가진 두개의 확장함수가 생긴다면 어떻게될까??
Conflicting overloads 라는 키워드를 통해서 코틀린 컴파일러 내에서 컴파일 에러를 보여준다.
오버로드 해결이 모호합니다. 이 모든 함수가 일치합니다.
- public fun String.getFirstWord(): Char defined in my.심화 in file 5_Extension2.kt
- public fun String.getFirstWord(): Char defined in my.심화 in file 5_Extension.kt
결과적으로 시그니처가 겹쳐서 선언되어있다면 코틀린 컴파일러에 의해 컴파일은 진행될 수 없다.