+ 항공대학교 김철기 교수님의 객체 지향 프로그래밍 과목 내용를 정리한 글입니다.
영역 함수 (Scope Function)
run, let, with apl, apply, also 라는 다섯가지 영역함수가 존재한다.
+ run - let - with, apply - also 간 유사성이 있다.
다섯 가지를 모두 능숙하게 사용할 필요는 없으나 유사성이 있는 영역함수 중 한 두개는 쓸 줄아는 것이 좋다.
다섯가지 영역 함수에 대한 코드를 읽을 줄은 알아야한다.
run 영역 함수
- 객체를 만들고 초기화하는 과정에서 많이 사용한다.
- run()의 인자인 람다함수는 수신 객체의 메소드처럼 정의한다.
=> 즉 this는 수신 객체이다.
- 마지막 문자의 반환값이 run()의 반환값이 된다.
- 수신 객체와 연관된 코드를 run 영역함수 내 람다함수로 모듈화하여 분리한다.
run 영역 함수를 사용하지 않은 코드
class Address {
var city: String = ""
var street: String = ""
var house: String = ""
fun post(message: String): String =
"Message for ($city, $street, $house): $message"
}
fun main() {
val addr = Address()
addr.city = "London"
addr.street = "Baker Street"
addr.house = "221b"
val msg = addr.post("Hello")
println(msg) // Message for (London, Baker Street, 221b): Hello!
}
run 영역 함수를 사용한 코드
class Address {
var city: String = ""
var street: String = ""
var house: String = ""
fun post(message: String): String =
"Message for ($city, $street, $house): $message"
}
fun main() {
val msg = Address().run {
// 이 영역 안에서는 Address 객체가 this가 된다.
city = "London"
street = "Baker Street"
house = "221b"
post("Hello!") // 마지막 줄의 내용이 반환 값이 된다.
}
println(msg) // Message for (London, Baker Street, 221b): Hello!
}
문맥이 없는 run 영역 함수
class Address(val city: String, val street: String, val house: String) {
fun asText() = "$city, $street, $house"
}
fun main() {
val city = readLine() ?: return
val street = readLine() ?: return
val house = readLine() ?: return
val address = Address(city, street, house)
println(address.asText()) // London, Baker Street, 221b
}
위 코드에서 main 함수의 첫 4줄은 address를 만들기 위한 코드이므로 영역 함수로 묶는 것이 바람직하다. (모듈화)
class Address(val city: String, val street: String, val house: String) {
fun asText() = "$city, $street, $house"
}
fun main() {
// 인스턴스 address를 run을 이용하여 생성
val address = run() {
val city = readLine() ?: return
val street = readLine() ?: return
val house = readLine() ?: return
Address(city, street, house)
}
println(address.asText()) // London, Baker Street, 221b
}
With 영역 함수
- run 영역 함수와 비슷하지만, run 앞에 올 객체를 with의 첫 인자로 받는다.
앞 예제를 with 영역 함수로 바꾼 코드
class Address {
var city: String = ""
var street: String = ""
var house: String = ""
fun post(message: String): String =
"Message for ($city, $street, $house): $message"
}
fun main() {
val msg = with(Address()) {
// 이 영역 안에서는 Address 객체가 this가 된다.
city = "London"
street = "Baker Street"
house = "221b"
post("Hello!") // 마지막 줄의 내용이 반환 값이 된다.
}
println(msg) // Message for (London, Baker Street, 221b): Hello!
}
let 영역 함수
- let 함수는 앞쪽에 오는 수신 객체가 뒤 람다 함수의 첫 번째 파라미터로 작용한다.
class Address {
var city: String = ""
var street: String = ""
var house: String = ""
fun post(message: String): String =
"Message for ($city, $street, $house): $message"
}
fun main() {
val msg = Address().let {
it.city = "London"
it.street = "Baker Street"
it.house = "221b"
it.post("Hello!")
}
println(msg) // Message for (London, Baker Street, 221b): Hello!
}
위 코드에서 it 대신 addr이라는 변수에 인스턴스를 할당하여 사용할 수 있다.
class Address {
var city: String = ""
var street: String = ""
var house: String = ""
fun post(message: String): String =
"Message for ($city, $street, $house): $message"
}
fun main() {
val msg = Address().let {addr ->
addr.city = "London"
addr.street = "Baker Street"
addr.house = "221b"
addr.post("Hello!")
}
println(msg) // Message for (London, Baker Street, 221b): Hello!
}
let을 이용한 널 안전성(?.) 처리
import java.lang.NumberFormatException
// 정수가 아닌 값이 들어오면 null을 반환한다.
fun readInt() = try {
readLine()?.toInt()
} catch (e: NumberFormatException) {
null
}
fun main() {
val arr = intArrayOf(3, 9, 7, 6, 4)
val num = readInt()
val result = if(num != null) arr.getOrNull(num) else null
// getOrNull: num이 arr의 인덱스를 벗어난 수라면 null, 아니라면 num에 해당하는 수를 반환한다.
if(result != null) {
println(result)
}
}
위 코드에서 result값을 설정할 때, if문을 사용하지 않으면 오류가 발생한다.
=> let 영역 함수를 이용하여 널 안정성을 보장하는 코드를 만들 수 있다.
import java.lang.NumberFormatException
// 정수가 아닌 값이 들어오면 null을 반환한다.
fun readInt() = try {
readLine()?.toInt()
} catch (e: NumberFormatException) {
null
}
fun main() {
val arr = intArrayOf(3, 9, 7, 6, 4)
val num = readInt()
val result = num?.let {num -> arr.getOrNull(num)}
// Int? 형 num 인스턴스를 null이 아니라고 간주하고, Int형 인자로 받는다. (it 사용 가능)
if(result != null) {
println(result)
}
}
apply, also 영역 함수
- apply는 run에 대응하지만 최종적으로 수신 객체를 반환한다.
class Address {
var city: String = ""
var street: String = ""
var house: String = ""
fun post(message: String): String =
"Message for ($city, $street, $house): $message"
}
fun main() {
val msg = Address().apply {
// 이 영역 안에서는 Address 객체가 this가 된다.
city = "London"
street = "Baker Street"
house = "221b"
}.post("Hello!")
// apply로 반환된 Address 인스턴스의 post함수를 호출하여 msg에 저장한다.
println(msg) // Message for (London, Baker Street, 221b): Hello!
}
- also는 let에 대응하지만 최종적으로 수신 객체를 반환한다.
class Address {
var city: String = ""
var street: String = ""
var house: String = ""
fun post(message: String): String =
"Message for ($city, $street, $house): $message"
}
fun main() {
val msg = Address().also {
// 이 영역 안에서는 Address 객체가 this가 된다.
it.city = "London"
it.street = "Baker Street"
it.house = "221b"
}.post("Hello!")
// also로 반환된 Address 인스턴스의 post함수를 호출하여 msg에 저장한다.
println(msg) // Message for (London, Baker Street, 221b): Hello!
}
'Study > Kotlin Study' 카테고리의 다른 글
[Kotlin] 하위 클래스 선언 (2) | 2023.10.23 |
---|---|
[Kotlin] Fragment 실습 (2) | 2023.10.14 |
[Kotlin] 확장 (0) | 2023.10.09 |
[Kotlin] 함수형 프로그래밍 (0) | 2023.09.22 |
[Kotlin] 객체 (Object) (0) | 2023.09.17 |