본문 바로가기
프로그래밍/Kotlin

[Kotlin](Scope Function) let, with, run, apply, also 차이 및 use

by Youngs_ 2021. 6. 7.

코틀린에서 let, with, run, apply, also라는 확장 함수가 있다 다섯가지의 확장함수는 조금씩 사용법이 비슷하면서 다른데, 그 의미를 알아보자

 

data class Person(var name : String ,var age : Int)

해당 객체를 이용하여 알아보겠습니다.

 

fun main(){
    val person = Person("", 0)
    person.name = "Youngs"
    person.age = 20
    println("$person")
}

위 코드는 일반적인 사용법입니다. 실행시 아래와 같은 결과값이 나옵니다.

1. let

fun <T, R> T.let(block: (T) -> R): R // let의 형태

let은 블록의 마지막 값에 따라 let의 return값 형태가 같이 달라진다.

 

fun main(){
    val person = Person("", 0)
    
val resultIt = person.let {
    it.name = "James"
    it.age = 56
    it // (T)->R 부분에서의 R에 해당하는 반환값.
}

val resultStr = person.let {
    it.name = "Steve"
    it.age = 59
    "이렇게 반환됩니다." // (T)->R 부분에서의 R에 해당하는 반환값.
}

val resultUnit = person.let {
    it.name = "Joe"
    it.age = 63
    // (T)->R 부분에서의 R에 해당하는 반환값 없음
}
println("$resultIt")
println("$resultStr")
println("$resultUnit")
}

 

let의 결과

val nameStr = person?.let { it.name } ?: "Defalut name"

위 코드처럼 ?.를 사용하여 nonNull체크시에 사용할 수 있고 ?:를 사용하여 기본 값을 지정 할 수 있다.

 

2. with

fun <T, R> with(receiver: T, block: T.() -> R): R // with의 형태

with(Person){}을 하면 {} 내에서 곧바로 name이나 age 프로퍼티에 접근할수 있다.

non-null의 객체를 사용하고 블럭의 return값이 필요하지 않을때 사용한다.

주로 객체의 함수를 여러개 호출 할 때 그룹화 하는 용도로 활용된다.

fun main(){
val person = Person("Youngs", 20)
    with(person) {
        println(name)
        println(age)
        //자기자신을 반환해야 하는 경우 it이 아닌 this를 사용한다
    }
}

 

3. run

run은 두가지 형태로 선언되어 있다.

fun <T, R> T.run(block: T.() -> R): R // 첫번째 형태
fun <R> run(block: () -> R): R // 두번째 형태

첫번째 형태는 .?를 붙여 nonNull일때만 실행할 수 있고, 어떤 값을 계산할 필요가 있거나 여러개의 지역변수 범위를 제한할때 사용한다.

 

두번째 형태는 어떤 객체를 생성하기 위한 명령문을 블럭 안에 묶음으로서 가독성을 높이는 역할을 한다

// 첫번째 형태
fun main(){
    val person = Person("Youngs", 20)
    val ageNextYear = person.run {
        ++age
    }

    println("$ageNextYear")
}

/////////////////////////////////////////////////////////////

// 두번째 형태
fun main(){
    val person = run {
    val name = "James"
    val age = 56
    Person(name, age)
	}
}

 

4. apply

fun <T> T.apply(block: T.() -> Unit): T

apply는 블럭 함수의 입력을 람다 리시버로 받았기 때문에 블럭 안에서 객체의 프로퍼티를 호출할때 it이나 this를 사용할 필요가 없다. run과 유사하지만 블럭에서 return값을 받지 않으며 자기 자신을 반환한다는 점이 다르다.

 

fun main(){
    val person = Person("", 0)
    val result = person.apply {
        name = "Youngs"
        age = 20
    }

    println("$person")
}

5. also

fun <T> T.also(block: (T) -> Unit): T // also의 형태

it을 사용해 프로퍼티에 접근하며, 객체의 속성을 전혀 사용하지 않거나 변경하지 않고 사용하는 경우 also를 사용한다.

객체의 데이터 유효성을 확인하거나, 디버그, 로깅 등의 부가적인 목적으로 사용할 때 적합하다.

 

fun main(){
    val person = Person("", 0)
    val result = person.also {
        it.name = "Youngs"
        it.age = 20
    }

    println("$person")
}

 

6. use

public inline fun <T : Closeable, R> T.use(block: (T) -> R): R

아래는 use의 예제코드이다.

D드라이브의 output.txt 파일에 hello 글자를 추가하는 코드이다.

\\를 두개 사용한 이유는 ""안에 \가 입력되게 하려면 \\를 입력해야 하기 때문이다.

fun main() {
    PrintWriter(FileOutputStream("D:\\output.txt")).use {
        it.println("hello")
    }
}

 

let

객체 결과값에 하나 이상의 함수를 호출하는 경우 사용합니다.

 

with

with 이미 생성된 Context Object 객체를 인자로 받아서 사용하는 것이 효율적일 때는 with 사용하면 좋습니다.

 

run

with 비슷한 역할로, 이미 생성된 Context Object 객체를 사용할 호출하며, with와는 전달받는 위치가 다릅니다.
그리고, 가장 중요한 차이점은 앞에 Safe Call (?.) 붙여서 null 체크까지 있기 때문에, with보다는 run 자주 사용되는 이유 하나라고 있습니다.

 

apply

apply 보통 객체 초기화 시에 가장 많이 사용됩니다.

 

also

also 기존 객체를 수정하거나 변경하지 않고, 디버깅을 위한 로깅 등의 추가적인 부가 작업을 하려고 사용합니다.

Function Context Object Return Value
let it Lambda result
run this Lambda result
with this Lambda result
apply this Context Object
also it Context Object

더보기

필자가 검색할때 사용할 검색어

apply 사용법
let 사용법
run 사용법
use 사용법
with 사용법

안드로이드 apply
안드로이드 let
안드로이드 run
안드로이드 use
안드로이드 with

'프로그래밍 > Kotlin' 카테고리의 다른 글

코틀린 에러 모음  (0) 2021.06.09
코틀린 문법 연습  (0) 2021.06.09
코틀린 코딩 연습  (0) 2021.06.07
[Android] Material Calendar 메소드 오류  (0) 2021.05.30
Java , Kotlin 차이점  (0) 2021.05.14

댓글