본문 바로가기

Study/Kotlin Study

[Kotlin] 확장

+ 항공대학교 김철기 교수님의 객체 지향 프로그래밍 과목 내용를 정리한 글입니다.

클래스 확장 함수

- 이미 존재하는 클래스의 새로운 멤버를 확장할 수 있다.

=> 실제로 클래스에 멤버를 추가하는 것이 아니다.

 

- 정의 후 기존 클래스 멤버와 동일하게 이용이 가능하다.

// String 객체에 truncate 함수 확장

// String을 maxLength 길이로 자르는 함수
fun String.truncate(maxLength: Int):String {
    return if(length <= maxLength) this else substring(0, maxLength)
    // 'this.'을 생략할 수 있다.
}

fun main() {
    println("Hello".truncate(10))
    println("Hello".truncate(3))
}

 

- 기존 클래스의 비공개 멤버에는 접근이 불가하다.

class Circle(private var radius: Double)

fun Circle.setRadius(newRadius: Double) {
    radius = newRadius // private으로 선언된 radius에 접근이 불가능하다.
}

fun main() {
    val c = Circle(10.0)
    c.setRadius(15.0)
}

 

위 코드에서 setRadius함수를 클래스에 직접 넣어 작성하면 접근이 가능하다.

class Circle(private var radius: Double) {
    fun setRadius(newRadius: Double) {
        radius = newRadius // private으로 선언된 radius에 접근이 불가능하다.
    }
}

fun main() {
    val c = Circle(10.0)
    c.setRadius(15.0)
}

 

- 기존 멤버와 동일한 멤버는 기존 멤버에 우선 순위가 부여된다.

=> 즉, 이미 클래스에 존재하는 함수와 동일한 이름의 함수는 만들 필요가 없다.


타 패키지의 확장 함수

- 타 패키지에 정의된 확장 함수는 import가 필요하다.

package kr.kau.util

// String을 maxLength 길이로 자르는 함수
fun String.truncate(maxLength: Int):String {
    return if(length <= maxLength) this else substring(0, maxLength)
    // 'this.'을 생략할 수 있다.
}
package kr.kau.main

import kr.kau.util.truncate // 타 패키지에 정의된 확장 함수를 사용하기 위해 import

fun main() {
    println("Hello".truncate(10))
    println("Hello".truncate(3))
}

클래스 확장 프로퍼티

- 확장 함수와 같이 프로퍼티도 확장이 가능하다.

- 뒷받침하는 필드(field) 사용이 불가능하기 때문에 get, set으로 정의하는 방법으로만 프로퍼티를 정의할 수 있다.

// Intrange 클래스에 leftHalf 프로퍼티 확장
val IntRange.leftHalf: IntRange // 절반 범위 반환
    get() = start .. (start + endInclusive) / 2

fun main() {
    println((1 .. 3).leftHalf) // 1 .. 2
}

동반 확장

// n ~ n 범위를 반환하는 동반 객체 확장 함수
fun IntRange.Companion.singletonRange(n: Int) = n .. n

fun main() {
    println(IntRange.singletonRange(3))
    println(IntRange.Companion.singletonRange(10))
}

 

- 동반 객체가 존재하는 경우에만 동반 객체 확장이 가능하다.

class Person(val firstName: String, val lastName: String) {
    companion object
}

val Person.Companion.UNKNOWN by lazy { Person("John", "Doe") } 
// UNKNOWN이 호출 될 때 정의된다.

fun main() {
    val p = Person.UNKNOWN
    println(p.firstName) // John
}

 

ex) 모든 타입의 최상위 타입인 Any의 경우 동반 객체가 없기 때문에 동반 확장이 불가능하다.


확장 예

// 문자열에 한글이 몇 개있는지 반환하는 함수
fun countKoreanChar(str: String): Int {
    var korCnt = 0
    for(i in 0 until str.length) {
        if(str[i] >= 0xAC00.toChar() && str[i] <= 0xD7AF.toChar()) {
            korCnt += 1
        }
    }
    return korCnt
}

fun main() {
    val str = readln() // 널처리를 하지 않아도 된다.

    println("$str has ${countKoreanChar(str)} Korean Characters")
}

 

위 코드를 확장 함수를 이용하면,

// 문자열에 한글이 몇 개있는지 반환하는 확장 함수
fun String.countKoreanChar(): Int {
    var korCnt = 0
    for(i in 0 until length) {
        if(this[i] >= 0xAC00.toChar() && this[i] <= 0xD7AF.toChar()) {
            korCnt += 1
        }
    }
    return korCnt
}

fun main() {
    val str = readln() // 널처리를 하지 않아도 된다.

    println("$str has ${str.countKoreanChar()} Korean Characters")
}

 

위 코드를 확장 프로퍼티로 작성하면,

// 문자열에 한글이 몇 개있는지를 갖는 확장 프로퍼티
val String.numOfKoreanChars: Int
    get() {
        var korCnt = 0
        for(i in 0 until length) {
            if(this[i] >= 0xAC00.toChar() && this[i] <= 0xD7AF.toChar()) {
                korCnt += 1
            }
        }
        return korCnt
    }


fun main() {
    val str = readln() // 널처리를 하지 않아도 된다.

    println("$str has ${str.numOfKoreanChars} Korean Characters")
}

'Study > Kotlin Study' 카테고리의 다른 글

[Kotlin] Fragment 실습  (2) 2023.10.14
[Kotlin] 영역 함수  (0) 2023.10.09
[Kotlin] 함수형 프로그래밍  (0) 2023.09.22
[Kotlin] 객체 (Object)  (0) 2023.09.17
[Kotlin] 단순한 변수 이상인 프로퍼티  (0) 2023.09.17