안녕세계
[Kotlin] Extension Functions (확장 함수) 본문
[Kotlin] Extension Functions (확장 함수)
Junhong Kim 2023. 6. 4. 16:03확장 함수란?
확장 함수는 Kotlin 기능 중 하나로, 기존 클래스에 새로운 함수를 추가하는 것 입니다. 즉, 이미 존재하는 클래스에 대해 확장 함수를 정의하여 해당 클래스의 인스턴스에서 멤버 함수처럼 호출할 수 있습니다. 확장 함수는 기존 클래스의 내부에 접근하지 않고도 외부에서 확장 함수를 작성하여 사용할 수 있습니다. 이를 통해 기존 클래스의 기능을 확장하거나, 특정 작업을 수행하는 유틸리티 함수를 제공할 수 있습니다.
확장 함수는 점 표기법을 사용하여 호출되며, 호출 대상 객체는 `수신 객체(receiver object)`라고 불립니다. 확장 함수를 선언할 때는 해당 확장 함수가 적용될 클래스를 수신 객체 타입으로 지정하고 그 뒤에 확장 함수 이름을 지정합니다. 그럼 이제 확장 함수를 선언하고 사용하는 방법에 대해 알아보겠습니다.
기본 문법
확장 함수 선언 방법
다음은 확장 함수의 선언 구문입니다.
fun 수신객체타입.확장함수명(): 반환값 {
// todo
}
- fun
- 함수를 선언합니다.
- 수신 객체 타입
- 확장 함수를 적용할 수신 객체 타입, 해당 클래스의 인스턴스로 확장 함수를 호출할 수 있습니다.
- 확장 함수
- 확장 함수의 이름, 일반적인 함수 선언 방법과 동일한 규칙을 따릅니다.
- 반환 값
- 확장 함수가 반환하는 결과 값
수신 객체 지정 람다와 함께 사용하기
수신 객체 지정 람다를 사용하면 확장 함수를 사용하는 동안 특정 객체를 더 쉽게 접근할 수 있습니다. 수신 객체 지정 람다는 함수 내에서 `this`를 사용해 수신 객체에 접근 할 수 있습니다. 예를 들어 수신 객체 지정 람다와 함께 사용하는 예시는 다음과 같습니다. 이 확장 함수는 List의 각 요소를 특정 조건에 따라 필터링한 결과를 반환합니다.
fun <T> List<T>.customFilter(predicate: (T) -> Boolean): List<T> {
val result = mutableListOf<T>()
for (item in this) {
if (predicate(item)) {
result.add(item)
}
}
return result
}
fun main() {
val list = listOf(1, 2, 3, 4)
val filteredList = list.customFilter { it % 2 == 0 }
println(filteredList)
}
--
[2, 4]
위 코드에서 `customFilter()` 함수를 호출할 때 수신 객체 지정 람다를 사용하여 필터링 조건을 지정합니다. 람다 내에서 `it` 키워드를 통해 현재 element에 접근할 수 있으며, 필터링 조건을 작성합니다. 이렇게 수정된 코드를 실행하면, `filteredList` 변수에는 주어진 List에서 짝수인 요소만 필터링된 새로운 List를 반환됩니다.
확장 함수 활용
기본 타입 확장 함수
기본 타입(Int, Double Boolean 등)에 대해 확장 함수를 작성할 수 있습니다. 확장 함수를 활용하여 기본 타입에 새로운 기능을 추가할 수있습니다. 예를 들어 숫자를 제곱하는 `square()` 확장 함수는 다음과 같습니다.
fun Int.square(): Int {
return this * this
}
fun main() {
val number = 2
val squaredNumber = number.square()
println(squaredNumber)
}
---
4
문자열 확장 함수
문자열에 대해 확장 함수를 작성할 수 있습니다. 기본 타입과 마찬가지로 확장 함수를 활용하여 문자열 타입에 새로운 기능을 추가할 수 있습니다. 예를 들어 주어진 문자열을 무작위로 섞는 `shuffle()` 확장 함수는 다음과 같습니다.
fun String.shuffle(): String {
val charArray = this.toCharArray()
charArray.shuffle()
return String(charArray)
}
fun main() {
val originalString = "HelloKotlin"
val shuffledString = originalString.shuffle()
println(shuffledString)
}
--
tlionlelHoK
컬렉션 확장 함수
컬렉션(List, Set, Map 등)에 대해 확장 함수를 작성할 수 있습니다. 확장 함수를 활용하여 컬렉션의 element를 처리하거나 변환하는 작업을 만들 수 있습니다. 예를 들어 List의 각 element를 제곱한 결과의 List를 반환하는 `square()` 확장 함수는 다음과 같습니다.
fun List<Int>.square(): List<Int> {
return this.map {
it * it
}
}
fun main() {
val list = listOf(1, 2, 3, 4)
println(list.square())
}
---
[1, 4, 9, 16]
파일 확장 함수
파일 다루기와 관련된 작업에도 확장 함수를 활용할 수 있습니다. 파일 확장 함수를 작성하여 파일을 보다 편리하게 조작하고 관리할 수 있습니다. 예를 들어 파일의 확장자를 반환하는 `getExtension()` 확장 함수는 다음과 같습니다.
fun File.getExtension(): String {
val fileName = this.name
val dotIndex = fileName.lastIndexOf(".")
return if (dotIndex > 0) fileName.substring(dotIndex + 1) else ""
}
fun main() {
val file = File("example.txt")
val extension = file.getExtension()
println(extension)
}
---
txt
확장 함수의 제약 사항
가시성과 접근 범위
확장 함수는 클래스의 멤버 함수처럼 호출할 수 있지만, 클래스 내부에서만 접근 가능한 private 멤버에는 접근할 수 없습니다. 예를 들어 다음과 같은 확장 함수에서 private 멤버인 `privateProperty`에 접근할 수 없습니다.
class MyClass {
private val privateProperty = "Private"
fun doSomething() {
println("Doing something")
}
}
fun MyClass.myExtensionFunction() {
println(privateProperty) // 컴파일 에러
doSomething()
}
확장 함수 내부에서는 확장 대상 클래스의 `public 멤버(doSomething)`에는 접근할 수 있지만 `private 멤버(privateProperty)`에는 접근할 수 없습니다.
이름 충돌
확장 함수를 정의할 때, 클래스의 멤버 함수와 동일한 이름으로 같은 시그니처를 가지는 함수가 있는 경우 이름 충돌이 발생합니다. 예를들어 이름 충돌이 발생하는 확장 함수는 다음과 같습니다.
class MyClass {
fun printInfo() {
println("Class method")
}
}
fun MyClass.printInfo() {
println("Extension method")
}
fun main() {
val myObject = MyClass()
myObject.printInfo() // `Class method` 출력
}
위 예시에서 MyClass에 `printInfo()`라는 멤버 함수와 확장 함수가 모두 존재합니다. 이 경우, 인스턴스의 `printInfo()`를 호출하면 클래스의 멤버 함수가 우선적으로 호출되어 `Class method`가 출력됩니다. 따라서, 확장 함수를 작성할 때는 클래스의 기존 멤버 함수와 이름 충돌이 발생하지 않도록 주의해야 합니다.
확장 함수는 언제 사용해야 할까?
기존 클래스에 새로운 기능을 추가하고 싶을 때
확장 함수는 기존 클래스의 코드를 수정하지 않고 새로운 기능을 추가할 수 있는 방법을 제공합니다. 따라서, 기존 클래스의 변경 없이 새로운 기능을 추가하고 싶을 때 확장 함수를 사용하여 기능을 확장합니다.
외부 라이브러리의 클래스에 기능을 추가하고 싶을 때
사용자 정의 클래스가 아닌 외부 라이브러리의 클래스처럼 직접 수정할 수 없는 클래스에도 확장 함수를 사용할 수있습니다. 이를 통해 외부 라이브러리의 클래스에 새로운 기능을 추가하거나 기존 기능을 확장할 수 있습니다.
코드의 가독성을 향상 시키고 싶을 때
확장 함수는 코드를 더 읽기 쉽고 자연스럽게 만들어 줍니다. 특히, DSL(Domain-Specific Language) 구축이나 특정 작업을 수행하는 함수를 작성할 때 확정 함수를 사용하면 가독성을 향상 시킬 수 있습니다. (참고: Kotlin DSL 간단히 알아보기)
일급 컬렉션이 필요할 때
자바에서는 특정 타입의 컬렉션에 추가 기능을 부여하기 위해 별도의 클래스를 생성하여 일급 컬렉션을 만드는 방법을 사용합니다. 코틀린에서는 일급 컬렉션 대신 확장 함수를 정의하는 컬렉션에 새로운 기능을 추가하는 방법을 고려해볼 수 있습니다.
참고
'Language > Kotlin' 카테고리의 다른 글
[Kotlin] 아키텍처 테스트 (feat. ArchUnit) (4) | 2024.10.31 |
---|---|
[Kotlin] 제네릭과 무공변 (feat. 공변, 반공변) (1) | 2024.03.31 |
[Kotlin] Higher-order Functions (고차 함수) (0) | 2023.07.02 |
[Kotlin] Delegation (위임) (0) | 2023.06.18 |
[Kotlin] Scope Functions 차이점 (2) | 2023.05.21 |