Kotlin의 범위 함수

jibmin jung·2022년 6월 11일
0

코틀린에는 어떤 객체의 컨텍스트 내에서 하나의 코드 블록을 실행시키는 것이 목적인 함수들이 있습니다.
어떤 객체에서 이 함수들을 람다 표현식과 함께 호출하면, 하나의 일시적인 범위(Scope)를 형성합니다.
우리는 이 범위 안에서 해당 객체에 객체 이름없이 접근할 수 있습니다.
이런 함수를 범위(Scope)함수라고 합니다.
범위함수를 잘 사용하면, 깔끔하고 보기 쉬운 코드를 작성할 수 있습니다.

종류

범위 함수에는 run,let,apply,also,with 다섯가지가 있습니다.
다섯가지 모두 제공된 코드 블록을 실행시키는데요, 범위 안에서 객체를 어떻게 참조하는지 그리고 무엇을 반환하는지가 다릅니다.

run

run은 객체를 this로 참조하고, 람다의 결과를 반환합니다.

fun main(){
val temp = System.`in`.bufferedReader().run{
        val input = this.readLine()
        "$input"
    }
    println(temp)
}
/*
>>>hello
hello
*/

run에 제공된 람다의 마지막 결과가 반환되어 temp에 저장되었습니다.
블록내부에서 객체에 접근할때 this를 써주었는데, 쓰지 않고 바로 메소드나 필드에 접근할 수 있습니다.

let

let은 객체를 it으로 참조하고, 람다의 결과를 반환합니다.

fun main(){
    val list = listOf(1,2,3,4,5,6,7)
    val processed = list.filter { it%2==0 }.let{
        println(it)
        it.map { it.times(2) }
    }
    println(processed)
}
/*
[2, 4, 6]
[4, 8, 12]
*/

그런데 it으로 참조하다보면 블록 내에서 다른 it과 겹치는 경우가 생깁니다.
위의 it.map{it.times(2)} 에서 앞의 it과 뒤의 it은 서로 다른 것을 가리킵니다.
앞의 it은 let의 컨텍스트 객체인 list.filter{it%2==0}를 가리키고,
뒤의 it은 map에서 사용되는 it으로 리스트의 원소인 Int입니다.
it이 겹치기 때문에,
let의 객체에 이름을 붙힘으로써, 가독성을 높일 수 있습니다.

fun main(){
    val list = listOf(1,2,3,4,5,6,7)
    val processed = list.filter { it%2==0 }.let{ filterdList ->
        println(filterdList)
        filterdList.map { it.times(2) }
    }
    println(processed)
}
/*
[2, 4, 6]
[4, 8, 12]
*/

let은 객체가 널이 아닌 경우에만 실행하고 싶은 블록이 있을 때에 잘 활용됩니다.
Safe Call이라고 불리는 " ?. " 을 활용합니다.

fun main(){
	fun query(i:Int):String?{
        return if(i==1) null else "Result"
    }
    var str = query(1)
    str?.let { //str이 널이기 때문에 실행되지 않음
        println("1")
        println(it)
    }
    str = query(2)
    str?.let { //str이 널이 아니기 때문에 실행됨
        println("2")
        println(it)
    }
}
/*
2
Result
*/

also

also 는 it으로 참조하고, 컨텍스트 객체를 반환합니다.

fun main(){
val list = listOf(1, 2, 3, 4, 5, 6, 7)
    val processed = list.filter { it % 2 == 0 }.also {
        println(it)
    }.filter { it > 4 }
    println(processed)
}
/*
[2, 4, 6]
[6]
*/

with

with 는 this로 참조하고, 람다 결과를 반환합니다.
그러나 이 함수를 사용할때는 람다 결과를 제공하지 않는 것을 추천한다고 합니다.

fun main(){
	val list = listOf(1, 2, 3, 4, 5, 6, 7)
    with(list) {
        println(size)
        println(indices)
        println(filter { it % 2 == 0 })
    }
}
/*
7
0..6
[2, 4, 6]
*/

마찬가지로 this 없이도 바로 메소드나 필드 참조 가능합니다.

apply

apply 는 it으로 참조하고, 컨텍스트 객체를 반환합니다.
apply는 초기화, 객체의 속성 설정 시에 잘 사용됩니다.

fun main(){
	data class Car(
        var color: String? = null,
        var type: String? = null,
    )
    val redCar = Car().apply {
        color = "RED"
        type = "SUV"
    }
    println(redCar)
}
/*
Car(color=RED, type=SUV)
*/

profile
이것저것 안드로이드

0개의 댓글