Kotlin의 확장 기능 차별화

David Mbochi Njonge 2023년1월30일
  1. Kotlin에서 확장 함수 만들기
  2. Kotlin에서 확장 함수와 함께 Lambda 함수 사용
  3. Kotlin에서 let() 확장 기능 사용
  4. Kotlin에서 also() 확장 기능 사용
  5. Kotlin에서 apply() 확장 기능 사용
  6. Kotlin에서 takeIf() 확장 기능 사용
  7. Kotlin에서 takeUnless() 확장 기능 사용
  8. 결론
Kotlin의 확장 기능 차별화

객체 지향 프로그래밍에서 우리는 상속, 캡슐화, 추상화 및 다형성의 개념을 배웠지만 유연하고 재사용 가능하며 유지 관리 가능한 방식으로 애플리케이션을 구조화하기에 충분하지 않습니다.

디자인 원칙과 OOP 개념의 도움으로 디자인 패턴은 일반적인 디자인 문제에 대한 솔루션을 소개하기 위해 구출되었습니다. 이 튜토리얼에서 다룰 것과 매우 유사한 디자인 패턴 중 하나는 데코레이터 디자인 패턴입니다.

데코레이터 디자인 패턴을 사용하면 다른 클래스에서 확장하지 않고도 애플리케이션에 기능을 추가할 수 있습니다. Kotlin에서는 Kotlin 확장 기능을 사용하여 디자인 패턴과 동일한 기능을 얻을 수 있습니다.

Kotlin의 확장 함수는 다른 클래스에서 확장하거나 데코레이터 디자인 패턴을 사용하지 않고 클래스에 기능을 추가합니다. 이면에서 확장 함수는 일반적일 수 있으며 람다 함수를 사용하여 우리가 언급한 기능을 실현할 수 있습니다.

이 자습서에서는 각 확장 기능에 대해 자세히 알아보고 각각에 대한 예를 제공합니다. 이 기사에서 다루는 확장 기능은 apply(), also(), let(), takeIf()takeUnless()입니다.

Kotlin에서 확장 함수 만들기

확장 함수를 생성하려면 문자열, 숫자 또는 클래스와 같이 기능을 추가할 형식을 정의하고 점 연산자를 사용하여 기능을 위임한 메서드를 정의합니다. 확장 함수의 반환 유형을 정의하고 마지막으로 같은 줄에 메서드의 논리를 구현합니다.

Intellij 코드 편집기로 이동하여 extension-exercise라는 새 프로젝트를 만듭니다. src 아래에 com.extension 폴더 구조를 만듭니다.

extension 폴더 아래에 Main.kt 파일을 만들고 다음 코드를 붙여넣습니다.

package com.extension

fun Number.isGreaterThanTen(): Boolean = this.toInt() > 10;

fun main() {
    val  num = 100;
    println(num.isGreaterThanTen());
}

위의 코드에서는 숫자가 10보다 큰지 확인하고 부울 값을 반환하는 유형 Number에 isGreaterThanTen()이라는 확장 함수를 정의했습니다.

이 시점부터 number 유형의 변수를 호출하면 위의 기본 메소드에서 볼 수 있는 것처럼 isGreaterThanTen() 메소드에 액세스할 수 있습니다.

위의 프로그램을 실행할 때 true의 부울 값이 콘솔에 기록됩니다.

true

Kotlin에서 확장 함수와 함께 Lambda 함수 사용

배후에서 람다 함수는 하나의 메서드만 포함하는 인터페이스로 정의할 수 있습니다. 람다 함수는 함수 이름을 지정하지 않고 구체적인 함수에 익명으로 전달되고 반환 유형은 화살표 기호를 사용하여 정의됩니다.

다른 파일을 만들고 이전 코드를 파일로 이동합니다. 빈 Main.kt 파일에 다음 예제를 복사하여 붙여넣습니다.

package com.extension

fun Number.isGreaterThanTen(block: (Number) -> Boolean): Boolean = block(this);

fun main() {
    val num = 100;
    println(num.isGreaterThanTen { number ->
        number.toInt() > 10
    })

}

위의 코드에서 람다 함수를 매개변수로 받아들이고 부울을 반환하는 isGreaterThanTen()이라는 확장 함수를 정의했습니다.

block이라는 이름의 람다 함수는 Number 유형의 매개변수를 수락하고 부울 값을 반환합니다. 람다 함수에서 반환된 이 부울 값은 확장 함수에 위임됩니다.

이전 예제와 비교하여 우리는 메인 함수 내에서 유형 Number의 변수에 대해 isGreaterThanTen()을 호출한 후 확장 함수의 논리를 정의합니다.

위의 코드를 실행하고 이전 예제와 동일한 결과를 얻었는지 확인하십시오. 출력은 아래와 같습니다.

true

Kotlin에서 let() 확장 기능 사용

이전 코드를 우리가 만든 새 파일로 이동하고 다음 코드를 Main.kt 파일에 붙여넣습니다.

package com.extension

inline fun <T, R> T.let(block: (T) -> R): R = block(this);

fun  main(){
    val num = 10;
    val result = num.let { number -> number.toString() }
    println(result);
    println(result::class.java.typeName);
}

let() 함수는 제네릭을 사용하여 정의됩니다. 즉, 모든 유형을 사용할 수 있습니다. let() 함수를 호출하는 객체는 람다 함수의 매개변수로 전달됩니다.

람다 함수는 let() 함수 내부에 정의되어 있으며 매개변수로 전달된 것과 다른 객체를 반환합니다.

let() 함수가 반환하는 값은 람다 함수가 반환하는 함수와 동일하므로 람다 함수 반환 값을 let() 함수에 위임했습니다.

기본 메서드에서 Number 유형의 변수를 정의하고 확장 함수를 호출하여 숫자의 문자열 표현을 반환합니다.

그런 다음 반환된 값과 해당 유형을 콘솔에 기록하여 확장 기능이 필요에 따라 작동하는지 확인합니다. 확장 함수에 전달된 형식은 숫자였지만 반환된 값은 아래와 같이 문자열이었습니다.

10
java.lang.String

Kotlin에서 also() 확장 기능 사용

이전 코드를 우리가 만든 새 파일로 이동하고 다음 코드를 빈 Main.kt 파일에 붙여넣습니다.

package com.extension

inline fun <T> T.also(block: (T) -> Unit): T {block(this); return  this}

fun main(){
    val  num = 10;
    num.also {i ->
        println(i == 10)
    }
}

also() 확장 함수를 호출하는 객체는 람다 함수의 매개변수로 전달됩니다. 람다 함수는 확장 함수의 인수로 정의되며 일반적으로 단위로 표시되는 값을 반환하지 않습니다.

also() 함수는 사용 중인 현재 변수를 반환하며, 이는 추가 계산을 위해 람다 함수에 위임됩니다. 주 함수에서 값이 10인지 확인하기 위해 람다 함수에 위임된 Number 유형의 변수를 정의했습니다.

코드를 실행하고 아래와 같이 true 값을 반환하는지 확인합니다.

true

Kotlin에서 apply() 확장 기능 사용

이전 코드를 우리가 만든 새 파일로 옮기고 다음 코드를 빈 Main.kt 파일에 붙여넣습니다.

package com.extension

inline fun <T> T.apply(block: T.() -> Unit): T {block(); return this}

fun main(){
    val num = 10;
    num.apply {
        println(toDouble());
    }
}

apply() 확장 함수를 호출하는 객체는 이 객체의 메서드 호출로 람다 함수의 매개변수에 전달됩니다. 람다 함수에는 반환 값이 없습니다.

정의는 람다 함수가 기능을 처리하기 때문에 메서드를 호출하기 위해 형식의 개체를 사용할 필요가 없음을 의미합니다. 이 경우 유형에서 필요한 메소드만 호출하면 됩니다.

메인 함수에서 Number 유형의 변수를 정의하고 apply() 메소드를 사용하여 toDouble() 메소드를 호출하여 Number를 Double로 변환했습니다. toDouble() 메서드를 호출하는 데 객체에 대한 참조가 사용되지 않았습니다.

위의 코드를 실행하고 콘솔에 기록된 값은 아래와 같이 Double입니다.

10.0

Kotlin에서 takeIf() 확장 기능 사용

이전 코드를 우리가 만든 새 파일로 이동하고 다음 코드를 빈 Main.kt 파일에 붙여넣습니다.

package com.extension

inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null

fun main() {
    val  num = 10;
    println(num.takeIf { i ->
        i.plus(10) < 30
    })
}

takeIf() 확장 함수를 호출하는 객체는 람다 함수의 매개변수로 전달됩니다. 람다 함수는 이 메서드의 인수로 전달되고 부울 값을 반환합니다.

확장 함수는 람다 식의 조건이 true로 평가되는 경우에만 호출 개체를 반환합니다. 그렇지 않으면 null 값을 반환합니다.

주 함수에서 takeIf()를 사용하여 이 숫자에 10을 더한 값이 30보다 작은지 확인하는 Number 유형의 값을 정의했습니다. 조건이 true로 평가되면 10 값이 반환됩니다. 그렇지 않으면 null 값이 반환됩니다.

위의 코드를 실행하고 아래와 같이 람다 표현식이 true로 평가되고 10 값이 반환됩니다.

10

Kotlin에서 takeUnless() 확장 기능 사용

이전 코드를 우리가 만든 새 파일로 이동하고 다음 코드를 복사하여 빈 Main.kt 파일에 붙여넣습니다.

package com.extension

inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? = if (!predicate(this)) this else null

fun main() {
    val num = 10;
    println(num.takeUnless { i ->
        i.plus(10) < 30
    })
}

takeUnless() 확장 함수를 호출하는 객체는 람다 함수의 매개변수로 전달됩니다. 람다 함수는 이 메서드에 정의되어 있으며 부울 값을 반환합니다.

takeIf()takeUnless()의 차이점은 이 예제는 람다 표현식이 false로 평가될 때만 값을 반환한다는 것입니다. 즉, 확장 함수에서 반환된 값은 람다 함수에서 반환된 부울 함수의 역함수입니다.

메인 메소드 내에서 위와 동일한 예제를 정의했지만 람다 함수가 true로 평가되고 false로 반전되기 때문에 이 예제는 null을 반환합니다.

null

결론

이 튜토리얼에서는 확장 기능을 사용하여 Kotlin에 기능을 추가하는 방법을 배웠습니다. 다루는 확장 기능에는 let(), also(), apply(), takeIf()takeUnless() 사용이 포함됩니다.

이러한 확장 기능은 이미 Kotlin API에 정의되어 있으므로 이 튜토리얼에서 했던 것처럼 정의할 필요가 없습니다.

David Mbochi Njonge avatar David Mbochi Njonge avatar

David is a back end developer with a major in computer science. He loves to solve problems using technology, learning new things, and making new friends. David is currently a technical writer who enjoys making hard concepts easier for other developers to understand and his work has been published on multiple sites.

LinkedIn GitHub