1. 고차함수
고차함수 : 다른 함수를 인자로 받거나, 함수를 받환하는 함수.
즉, 코틀린에서는 람다나 함수 참조를 인자로 넘길 수 있거나 람다나 함수 참조를 반환하는 함수이다.
1. 함수 타입
- (Int, String) → Unit (파라미터타입 → 반환타입)
- () → String? null을 반환할 수 있다.
- (() → Int)? 함수 타입이 null이 될 수 있다.
- invoke(이름 없이 간편하게 호출될 수 있는 함수)로 호출한다.
2. 인자로 받은 함수 호출
- 예제1
twoAndThree { a, b -> a + b } // The result is 5
twoAndThree { a, b -> a * b } // The result is 6
- 예제2
String.filter(predicate: (Char) -> Boolean): String {
val sb = StringBuilder()
for (index in 0 until length) {
val element = get(index)
if (predicate(element)) { // Boolean
sb.append(element)
}
}
return sb.toString()
}
println("ab1c".filter { it in 'a'..'z' } ) // abc
3. 널이 될 수 있는 함수 타입 파라미터
fun <T> Collection<T>.joinToString(
separator: String = ", ",
prefix: String = "",
postfix: String = "",
transform: ((T) -> String)? = null
) : String {
val result = StringBuilder(prefix)
for((index, element) in this.withIndex()) {
if (index > 0) result.append(separator)
val str = transform?.invoke(element) ?: element.toString()
result.append(str)
}
result.append(postfix)
return result.toString()
}
4. 람다를 활용한 중복 제거
enum class OS { WINDOWS, LINUX, MAC, IOS, ANDROID }
fun List<SiteVisit>.averageDurationFor(predicate: (SiteVisit) -> Boolean) =
filter(predicate) // 람다로 입력 filter
.map(SiteVisit::duration) // 사용시간
.average() // 평균
// 사용
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),
)
println(log.averageDurationFor { it.os in setOf(OS.ANDROID, OS.IOS) } )
2. inline 함수 : 람다의 부가 비용 없애기
- 람다식을 사용할 때마다 새로운 클래스가 만들어지지 않는다.
- 람다가 변수를 포획하면 람다가 생성되는 시점마다 새로운 무명 클래스 객체가 생긴다.
- 부가비용 발생 → 덜 효율적
1. 작동 방식
inline 선언시 함수 본문이 인라인된다. → 바이트코드로 컴파일한다.
- 바이트코드로 컴파일 한다는 것은, 람다를 호출하는 코드 정의의 일부분으로 간주되기 때문에 무명 클래스로 감싸지 않는다.
2. 한계
- 파라미터로 받은 람다를 다른 변수에 저장하고, 나중에 그 변수를 사용한다면 람다를 inline할 수 없다. (람다를 표현하는 객체가 어딘가 존재해야 하기 때문)
- 둘 이상의 람다를 인자를 받고, 일부 람다만 인라이닝 하고 싶은 경우 → noinline
- inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) {}
3. 컬렉션의 filter, map
- 컬렉션 연산 함수는 inline 함수이다. 따라서, 바이트코드는 거의 같다(for문으로 한 경우와).
- 하지만, 중간리스트를 생성한다.
- 처리할 경우가 적은 경우 → 컬렉션연산
- 처리할 경우가 많은 경우 → asSequence, 이는 inline 되지 않는다.
4. inline 함수, 언제사용할까
→ 람다를 인자로 받는 경우
- 주의점은?
- inline 함수가 큰 경우 함수 본문의 바이트코드가 전체적으로 커질 수 있다.
3. 람다 return
1. non-local return return
fun lookForAlice(people: List<Person>){
people.forEach {
if (it.name == "Alice") {
println("Found!")
return // non-local
}
}
println("Alice is not Found")
}
- 수행과정
- 함수실행을 끝낸다.
- 반환한다.
- non-local
- 자신을 둘러싸고 있는 블록보다 더 바깥에 있는 다른 블록을 반환
- 람다를 인자로 받는 ****함수가 인라인 함수인 경우에만 가능(forEach 등)
2. 로컬 return return@----
for의 break와 비슷한 역할
- 수행과정
- 함수실행을 끝낸다.
- 코드 실행을 이어간다.
fun lookForAlice(people: List<Person>) {
people.forEach label@{
if (it.name == "Alice") {
return@label // 인라인함수 이름 사용가능 return@forEach
}
}
println("항상실행구문")
}
3. 무명 함수 return
- 함수의 이름이나 파라미터 타입을 생략할 수 있다.
- return은 가장 가까운 함수를 가리킨다.
- 람다 식에 대한 문법적 편의일 뿐이다.
kotlin in action 책을 통한 공부입니다.
'공부 > Kotlin' 카테고리의 다른 글
10장 애노테이션과 리플렉션 (0) | 2022.07.18 |
---|---|
9장 제네릭스 (0) | 2022.07.02 |
[Kotlin] 연산자 오버로딩과 기타 관례 사용해보기 (0) | 2022.06.20 |
[Kotlin] 코틀린 타입 시스템 사용해보기 (0) | 2022.06.20 |
4장. 클래스, 객체, 인터페이스 (0) | 2022.06.07 |
댓글