[Kotlin] apply, with, let, also, run, 범위 지정, 수신 객체 지정 람다, 확장함수

2021. 6. 21. 11:15모바일/Android_Kotlin

[Kotlin] apply, with, let, also, run, 범위 지정, 수신 객체 지정 람다, 확장함수

확장함수란?

  • Extension functions(확장 함수)는 기존에 정의된 클래스에 함수를 추가하는 기능입니다. 자신이 만든 클래스는 새로운 함수가 필요할 때 쉽게 추가할 수 있는데요. Standard Library 또는 다른 사람이 만든 라이브러리를 사용할 때 함수를 추가하기가 매우 어렵습니다.

확장함수 정의법

fun List<Int>.getHigherThan(num: Int): List<Int> {
    val result = arrayListOf<Int>()
    for (item in this) {
        if (item > num) {
            result.add(item)
        }
    }
    return result
}
출처 : https://codechacha.com/ko/kotlin-extension-functions/

수신 객체 지정 람다란?

  • 함수 작성 시 사용하는 객체를 반복해서 명시하는 경우가 많다.
  • 이런 객체들을 함수안에서 명시 하지 않고 람다 본문 안에서 다른객체의 메소드를 호출할 수 있게 하는 람다

범위 지정 함수란?

  • 2가지 구성 요소를 갖는다.
  • 수신객체
  • 수신 객체 지정 람다

5가지 함수

inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    return receiver.block()
}
inline fun <T> T.also(block: (T) -> Unit): T {
    block(this)
    return this
}
inline fun <T> T.apply(block: T.() -> Unit): T {
    block()
    return this
}
inline fun <T, R> T.let(block: (T) -> R): R {
    return block(this)
}
inline fun <T, R> T.run(block: T.() -> R): R {
    return block()
}

with

  • Non-nullable (Null 이 될수 없는) 수신 객체
  • 명시적으로 수신객체가 지정된다
return with(stringBuilder){
    for(letter in 'A'..'Z'){
        this.append(letter)
    }
    append("알파벳")
    this.toString()
}

//////

fun alphablet(): String = with(StringBulder()){
      for(letter in 'A'...'Z'){
        append(letter)
    }
    append("알파벳")
    toString()
}
  • with(stringBuilder,{....}) 와 같다

with 2

class Person {
    var name: String? = null
    var age: Int? = null
}val person: Person = getPerson()
print(person.name)
print(person.age)

다음 코드는 person 의 중복 사용을 제거하기 위해 범위 지정 함수 with 를 사용한다는 점을 제외하고는 위와 동일합니다.

val person: Person = getPerson()
with(person) {
    print(name)
    print(age)
}

apply

  • 항상 자신에게 전달된(수신) 객체를 반환한다.
  • with함수와 거의 같다
  • 수신 객체 람다 내부에서 수신 객체의 함수를 사용하지 않고 수신 객체 의 프로퍼티 만을 사용
  • 객체 초기화시 주로 사용
  • apply는 객체의 property 값을 적용할 때 사용한다
fun alphabet(): String = StringBuilder().apply{
    for(letter in 'A'...'Z'){
        append(letter)
    }
    append("알파벳")
}.toString()

with vs apply

  • With returns the last line in the lambda as the result of the expression.
    • with는 람다식 내의 마지막 문장라인을 돌려준다
  • Apply returns the object that was passed in as the receiver as the result of the lambda expression.
    • apply는 리시버로 보낸 객체를 돌려준다

also

  • 객체의 사이드 이펙트 확인
  • 수신 객체의 프로퍼티에 데이터를 할당하기 전에 해당 데이터 유효성 검사 시 유용하게 사용
  • 수신 객체 람다가 전달된 수신 객체 사용x
  • 수신 객체의 속성 변경하지 않고 사용
    // 범위 지정 함수를 사용하지 않는 예
    println(person.age)
    println(person.name)

    // 범위 지정 함수를 사용하는 예 1
    with(person) {
        println(age)
        println(name)
    }

    // 범위 지정 함수를 사용하는 예 2
    person.also {
        println(it.age)
        println(it.name)
    }

let

  • 지정된 값이 null이 아닌 경우에 코드 실행(null 이면 프로그램이 죽지는 않고 다음 코드 실행)
val stocks : 보유종목가져오기함수()
stocks?.let{

}?:run{

}
  • 단일 지역 변수의 범위를 제한 하는경우

run

  • 어떤 값을 계산할 필요가 있거나 여러개의 지역 변수의 범위를 제한하려면 run 을 사용합니다.
  • run()은 이미 생성된 객체에 연속된 작업이 필요할 때 사용
val inserted: Boolean = run {
    // person 과 personDao 의 범위를 제한 합니다.
    val person: Person = getPerson()
    val personDao: PersonDao = getPersonDao()    // 수행 결과를 반환 합니다.
    personDao.insert(person)
}
fun printAge(person: Person) = person.run {
    // person 을 수신객체로 변환하여 age 값을 사용합니다.
    print(age)
}

run 을 사용하지 않는 동일한 코드는 다음과 같습니다.

val person: Person = getPerson()
val personDao: PersonDao = getPersonDao()
val inserted: Boolean = personDao.insert(person)
fun printAge(person: Person) = {
    print(person.age)
}

run2

data class WHAT(var name: String, var age: Int)
fun main() {
    val v = run {
        val w = WHAT("Jackass", 16)
        w
    }
    println(v)
    val vv = v.run {
        name = "Dip2K"
        age = 43
        "Good day !"
    }
    println(v)
    println(vv)
}

//출력
WHAT(name=Jackass, age=16)
WHAT(name=Dip2K, age=43)
Good day !

출처 : https://medium.com/@limgyumin/%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%9D%98-apply-with-let-also-run-%EC%9D%80-%EC%96%B8%EC%A0%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94%EA%B0%80-4a517292df29

http://www.gisdeveloper.co.kr/?p=10607