수신 객체가 있는 호출 가능 참조
- kotlin에서는 수신 객체가 있는 호출 가능한 참조를 만들 수 있다.
- 클래스 멤버, 확장 선언 등을 바탕으로 만들 수 있다.
fun aggregate(numbers: IntArray, op: Int.(Int) -> Int): Int {
var result = numbers.firstOrNull() ?: throw IllegalArgumentException("Empty")
for ( i in 1 .. numbers.lastIndex ) result = result.op(numbers[i])
return result
}
fun Int.max(other: Int) = if ( this > other ) this else other
fun main() {
val numbers = intArrayOf(1, 2, 3, 4)
println(aggregate(numbers, Int::plus))
println(aggregate(numbers, Int::max))
}
영역함수
- kotlin 내부에서 문맥 내부에서 임시로 사용할 수 있게 해주는 몇 가지 함수가 있다.
-
기본적으로 인자로 제공한 람다를 간단하게 실행해 주는 것이다.
- 문맥 식을 계산한 값을 영역 함수로 전달할 때 수신 객체로 전달하는가? 아니면 일반적인 함수 인자로 전달하는가?
- 영역함수가 확장 함수인 경우 vs. 영역 함수가 일반 함수인 경우
- 영역 함수의 람다 파라미터가 수신 객체 지정 람다인가? 아닌가?
- 영역 함수가 반환하는 값이 람다의 결과 값인가 컨텍스트 식을 계산한 값인가?
- 문맥 식을 계산한 값을 영역 함수로 전달할 때 수신 객체로 전달하는가? 아니면 일반적인 함수 인자로 전달하는가?
run, with
- run: 확장 람다를 받는 확장 함수, 람다의 결과를 돌려준다.
- with: run과 유사하지만 확장 함수 타입이 아니므로 문맥 식을 with에 던져야 한다.
class Address {
var zipCode: Int = 0
var city: String = ""
var street: String = ""
var house: String = ""
constructor()
constructor(city: String, street: String, house: String) {
this.city = city
this.street = street
this.house = house
}
}
fun main() {
Address().run {
zipCode = 1234
city = "Daejeon"
street = "yusung"
house = "Chunggu"
}
with(Address("Daejeon", "yusung", "Chunggu")) {
"Address $city $street $house"
}
}
문맥 없는 run
- run()을 오버로딩한 함수도 제공한다. 문맥 식이 없고 람다의 값을 반환하기만 한다.
- 수신 객체도, 파라미터도 없다.
- 그냥 블록을 두는 것 정도로 보면 된다.
class Address(city: String, street: String, house: String)
run {
city = "Daejeon"
street = "yusung"
house = "Chunggu"
Address(city, street, house)
}
let
- run과 유사하지만 확장 함수 타입의 람다를 받지 않고 인자가 하나인 함수 타입의 람다를 받는다.
- let의 반환 값은 람다가 반환하는 값과 같다.
- 외부 영역에 새로운 변수를 도입하는 일을 피하고 싶을 떄 사용한다. ```kotlin class Address(city: String, street: String, house: String) { fun post (): Unit { println(“$city $street $house”) } }
Address(“Daejeon”, “yusung”, “Chunggu”).let { //it로 Address에 접근 가능 it.post() }
- null이 될 수 있는 값을 안정성 검사를 거쳐서 null이 될 수 없는 함수에 전달하는 용법이 있다.
## apply/also
- apply 확장 함수는 확장 람다를 받는 확장 함수이며, 자신의 수신 객체를 반환한다.
- run과 달리 반환 값 없이 객체 상태를 설정하는 경우 사용한다.
```kotlin
class Address(){
var city: String = ""
var street: String = ""
var house: String = ""
}
Address().also {
it.city = "Daejeon"
it.street = "Expo"
it.house = "Chunggu"
}
클래스 멤버인 확장
- 클래스 멤버로 확장 함수를 선언할 수 있다.
- 최상위 확장과 달리 확장 수신 객체(extension receiver), 디스패치 수신 객체(dispatch receiver)가 있다.
class Address(val city: String, val street: String, val house: String) class Person(val firstName: String, val familyName: String) { fun Address.post(message: String ) { val city = city val street = this.street val house = this@post.house val firstName = firstName val familyName = this@Person.familyName } } - 복잡하다. 보퉁 최상위 확장이 간단하고 읽기 보기 좋은 코드를 만든다.