Kotlin Examples > Functional

HH·2022년 3월 11일
0

Kotlin Examples

목록 보기
5/8

2022-03-10 작성완료

Higher-Order Functions


Higher-Order Function은 다른 함수를 파라미터로 가지고/가지거나 함수를 반환하는 함수이다.


함수를 파라미터로 가짐


fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {  // 1
    return operation(x, y)                                          // 2
}

fun sum(x: Int, y: Int) = x + y                                     // 3

fun main() {
    val sumResult = calculate(4, 5, ::sum)                          // 4
    val mulResult = calculate(4, 5) { a, b -> a * b }               // 5
    println("sumResult $sumResult, mulResult $mulResult")
}
  1. 고차 함수를 선언한다. 이것은 두 정수 파라미터 xy를 가진다. 그리고 다른 함수 operation을 파라미터로 가진다. operation 파라미터와 리턴 타입 또한 선언에서 정의된다.
  2. 고차 함수는 제공된 아규먼트로 호출된 operation의 결과를 리턴한다.
  3. operation signature와 일치하는 함수를 선언한다.
  4. 두 정수 값과 함수 아규먼트 ::sum을 전달해 고차 함수를 호출한다. ::는 코틀린에서 함수를 이름으로 참조하는 표기법이다.
  5. 람다를 함수 아규먼트로써 전달해 고차함수를 호출한다. 더 깔끔해보이지 않는지?

함수를 반환함


fun operation(): (Int) -> Int {                                     // 1
    return ::square
}

fun square(x: Int) = x * x                                          // 2

fun main() {
    val func = operation()                                          // 3
    println(func(2))                                                // 4
}
  1. 함수를 반환하는 고차함수를 선언한다. (Int) -> Intsquare 함수의 파라미터와 반환값을 나타낸다.
  2. 시그니처와 일치하는 함수를 선언한다.
  3. 결과를 변수에 할당하기 위해 operation을 호출한다. 이 funcoperation에 의해 반환된 square가 된다.
  4. func를 호출한다. square 함수가 실제로 실행된다.

Lambda Functions


Lambda Functions("람다")는 애드혹 함수를 만드는 간단한 방법이다. 타입 추론과 암묵적 it 변수 덕에, 람다는 많은 경우 아주 간결하게 표시될 수 있다.

// All examples create a function object that performs upper-casing.
// So it's a function from String to String

val upperCase1: (String) -> String = { str: String -> str.uppercase() } // 1

val upperCase2: (String) -> String = { str -> str.uppercase() }         // 2

val upperCase3 = { str: String -> str.uppercase() }                     // 3

// val upperCase4 = { str -> str.uppercase() }                          // 4

val upperCase5: (String) -> String = { it.uppercase() }                 // 5

val upperCase6: (String) -> String = String::uppercase                  // 6

println(upperCase1("hello"))
println(upperCase2("hello"))
println(upperCase3("hello"))
println(upperCase5("hello"))
println(upperCase6("hello"))
  1. 모든 곳에 명시적 타입이 있는 람다. 람다는 중괄호 안에 있는 부분이고, (String) -> String 타입(함수 타입) 변수에 할당된다.
  2. 람다 내부 타입 추론: 람다 파라미터의 타입이 그 람다가 할당된 타입으로부터 추론된다.
  3. 람다 외부 타입 추론: 변수의 타입이 람다 파라미터와 리턴값으로부터 추론된다.
  4. 이 둘을 함께 할 수는 없다. 컴파일러는 타입을 추론할 수 없다.
  5. 단일 파라미터를 가진 람다는 명시적으로 파라미터를 언급할 필요가 없다. 대신 암묵적인 it 변수를 사용할 수 있다. 이것은 it 타입이 추론될 수 있을 때(자주 있는 일이다) 특히 유용하다.
  6. 람다가 단일 함수 호출로 구성될 경우 함수 포인터 ::를 쓸 수 있다.

Extension Functions and Properties


코틀린은 어떤 클래스에든 확장(extensions) 메커니즘으로 새 멤버를 추가할 수 있다. 즉, 확장에는 두 가지 유형이 있다: 확장 함수(extension functions)와 확장 프로퍼티(extension properties)이다. 그것들은 일반적인 함수와 프로퍼티처럼 보이지만 한 가지 중요한 차이점이 있다: 확장하는 타입을 지정해야 한다.

data class Item(val name: String, val price: Float)                                         // 1  

data class Order(val items: Collection<Item>)  

fun Order.maxPricedItemValue(): Float = this.items.maxByOrNull { it.price }?.price ?: 0F    // 2  
fun Order.maxPricedItemName() = this.items.maxByOrNull { it.price }?.name ?: "NO_PRODUCTS"

//프로퍼티 commaDelimitedItemNames
val Order.commaDelimitedItemNames: String
//getter 작성                                                   
    get() = items.map { it.name }.joinToString()                                            // 3

fun main() {

    val order = Order(listOf(Item("Bread", 25.0F), Item("Wine", 29.0F), Item("Water", 12.0F)))
    
    println("Max priced item name: ${order.maxPricedItemName()}")                           // 4
    println("Max priced item value: ${order.maxPricedItemValue()}")
    println("Items: ${order.commaDelimitedItemNames}")                                      // 5

}
  1. ItemOrder의 단순한 모델을 정의한다. OrderItem 객체 컬렉션을 가질 수 있다.
  2. Order 타입에 확장 함수를 추가한다.
  3. Order 타입에 확장 함수를 추가한다.
  4. Order 인스턴스에서 확장 함수를 직접 호출한다.
  5. Order 인스턴스에서 확장 프로퍼티에 접근한다.

null 참조에서도 확장을 실행할 수 있다. 확장 함수 내에서 객체가 null인지 체크하고 그 결과를 코드에서 사용할 수 있다:

fun <T> T?.nullSafeToString() = this?.toString() ?: "Null"

0개의 댓글