독서관련/Kotlin in Action
CH08 코틀린 고차함수
ColinKang
2021. 1. 28. 22:16
아래의 글은 드미트리 제메로프, 스베트라나 이사코바 저/오현석역,『Kotlin in Action』,에이콘출판사(2017)의 내용을 기반으로 작성하였습니다.
고차 함수 : high order function : 다른 함수를 인자로 받거나 함수를 반환하는 함수 예 list.filter(x > 0)
고차 함수 정의 : 함수 타입 : 함수 문법 : (Int, String) -> Unit : 파라미터 타입 -> 반환타입
val sum : (Int, Int) -> Int = { x, y -> x + y }
val action: () -> Unit = { println(42) }
// 반환 타입 null 될 수 있음
val canReturnNull: (Int, Int) -> Int? = { x, y => null }
// 널이 될 수 있는 함수 타입 변수 정의
var funOrNull: ((Int, Int) -> Int)? = null
인자로 받은 함수 호출
fun String.filter(predicate: (Char) -> Boolean): String
fun String.filter(predicate: (Char) -> Boolean) : String {
val sb = StringBuilder()
// length = String 내 length
for (index in 0 until length) {
val element = get(index)
if (predicate(element) sb.append(element)
}
return sb.toString()
}
>>> println("ab1c".filter{ it in 'a'..'z'}
abc
fun <T> Collection<T>.joinToString (
seperator: String = "",
prefix: String = "",
postfix: Sring = ""
) : String {
val result = StringBuilder(prefix)
for ((index, element) in this.withIndex()) {
if (index > 0) result.append(prefix)
result.append(element)
}
result.append(postfix)
return result.toString()
}
fun <T> Collection<T>.joinToString (
seperator: String = "",
prefix: String = "",
postfix: Sring = "",
tranform: (T) -> String = { it.toString() }
) : String {
val result = StringBuilder(prefix)
for ((index, element) in this.withIndex()) {
if (index > 0) result.append(prefix)
result.append(transform(element))
}
result.append(postfix)
return result.toString()
}
>>> val letters = listOf("Alpha", "Beta")
>>> println(letters.joinToString())
Alpha, Beta
>>> println(letters.joinToString { it.toLowerCase() } )
alpha, beta
>>> println(letters.joinToString(seperator = "! ", postfix = "!", transform = { it.toUpperCase() }))
ALPHA! BETA!
fun <T> Collection<T>.joinToString (
seperator: String = "",
prefix: String = "",
postfix: Sring = "",
tranform: ((T) -> String)? = null
) : String {
val result = StringBuilder(prefix)
for ((index, element) in this.withIndex()) {
if (index > 0) result.append(prefix)
val str = transform?.invoke()
?: element.toString()
result.append(str)
}
result.append(postfix)
return result.toString()
}
함수에서 함수 반환
enum class Delivery { STANDARD, EXPRESS }
class Order(val itemCount: Int)
fun getShippingCostCalculator(delivery: Delivery): (Order) -> Double {
if (delivery == Delivery.EXPRESS) {
return { order -> 2.0 * order.itemCount }
}
return { order -> 1.5 * order.itemCount }
}
data class Person{
val firtName: String,
val lastName: String,
val phoneNumber: String?
}
class ContactListFilters {
var prefix: String = ""
var onlyWithPhoneNumber: Boolean = false
fun getPredicate(): (Person) -> Boolean {
val startWithPrefix = { p: Person ->
p.firstName.startWith(prefix) || p.lastName.startWith(prefix)
}
if (!onlyWithPhoneNumber) {
return startWithPrefix
}
return { startWithPrefix(it) && it.phoneNumber != null}
}
}
data class SiteVisit(
val path: String,
val duration: Double,
val os: OS
)
enum class OS { WINDOW, LINUX, MAC, IOS, ANDROID }
val log = listOf(
SiteVisit("/", 34.0, OS.WINDOWS),
SiteVisit("/", 22.0, OS.MAC),
SiteVisit("/login", 12.0, OS.WINDOWS),
SiteVisit("/signup", 8.0, OS.IOS),
SiteVisit("/", 16.3, OS.ANDROID),
)
fun List<SiteVisit>.averageDurationFor(predicate: (SiteVisit) -> Boolean) =
filter(predicate).map(SiteVisit::duration).average()
>>> println(log.averageDurationFor { it.os == OS.IOS && it.path = "/signup" })
함수 inline, noline
use 함수
withLock함수
non-local변환 : 자신을 둘러싸고 있는 블록보다 더 바깥에 있는 다른 블록을 반환하게 만드는 return문 non-local : 인라인 함수인 경우
return이 바깥쪽 함수를 반환시킨다
인라인 되지 않는 함수에 전달되는 람다안에서 return을 사용할 수 없다.
로컬 return : 람다의 실행을 끝내고 람다를 호출했던 코드이 실행을 계속 이어간다.
return으로 실행을 끝내고 싶은 람다 식 앞에 레이블 lable@ return뒤에 그 레이블 추가
람다식에는 레이블이 2개 이상 붙을 수 없다.
무명함수는 : 코드 블록을 함수에 넘길 때 사용할 수 있는 다른 방법이다.
fun lookForAlice(people: List<Persion>) {
// returned
people.forEach(fun(person) {
if (person.name == "Alice") return
}
}
//returned
fun lookForAlice(people: List<Person>) {
people.forEach {
if (it.name == "Alice") return
}
}