Scope Function

노지환·2022년 1월 26일
0
post-custom-banner

Scope Function에는 5가지 함수들이 존재합니다!

  • let, run, with
  • apply, also

Scope Function에 해당하는 함수들을 람다식을 이용하여 호출하면 일시적인 Scope(범위)가 생기고

이 범위 안에서는 전달된 객체에 대해 “it” 또는 “this”라는 Context Object를 통하여 접근할 수 있습니다.

scope function 간 차이점

이 함수들에는 두가지 차이점이 있습니다.

  • Context Object를 참조하는 방법(it, this)
  • Return value

Context Object?

Scope Function 람다식 안에서 Context Object는 실제 객체명을 대신하여, this나 it을 통해 객체에 접근합니다.

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

fun main() {
    val person = Person("노지환", 25)

    person.run {
        println("이름: ${this.name}") // this를 사용하여 진행할 수 있습니다.
        println("나이: $age") // this를 생략해도 됩니다!
        age = 26
    }
    println(person.age)

    person.let {
        println("이름: ${it.name}") //it은 생략할 수 없습니다!
        println("나이: ${it.age}")
        it.age = 25
    }
}

this

run, with, apply는 Context Object를 “this”로 참조합니다!

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

fun main() {
    val person = Person("노지환", 25)

    person.run {
        println("이름: ${this.name}")
        println("나이: $age")
    }

    with(person) {
        println("이름: ${this.name}")
        println("나이: $age")
    }

    person.apply {
        println("이름: ${this.name}")
        println("나이: $age")
    }
}

it

let, also는 Context Object를 “it”으로 참조합니다.

		person.let { want -> // 이런식으로 전달 인자명을 설정할 수도 있습니다!
        println("이름: ${want.name}")
        want.name = "지환노"
    }

    person.also {
        println("이름: ${it.name}")
    }

Return Value

  • apply, also는 Context Object를 반환하고,
  • let, run, with는 람다식 결과를 반환합니다!

Context Object

apply, also의 반환값은 Context Object 객체 자체입니다.

따라서, 체인 형식으로 계속 호출이 가능합니다!

		val numberList: MutableList<Double> = mutableListOf()
    numberList.also { println("Populating the list") } // 이런식으로
        .apply { // 연속적으로 사용하더라도, 반환값이 객체이기 때문에 사용이 가능하다!
            add(2.71)
            add(2.3)
            add(4.5)
            for (i in this) println(i)
        }
        .also { println("sorting") }
        .sort() // 하지만 sort후에는
        .run { // 반환값이 true, false이기 때문에 run을 사용할 때 this를 사용할 수 없다
            for(i in numberList) println(i)
        }
				//.run 이 친구도 사용이 불가능하다! run의 return 값은 람다식 결과를 반환하기 때문에 객체를 가져올 수 없다.

게다가 Context Object를 반환하는 함수의 return 문에도 사용이 가능합니다!

fun getNumber(): Int {
	return Random.nextInt(100).also {
			println("return random number")
	}
}

Lambda Result

  • let, run, with는 람다식 결과를 반환합니다.
  • 결과를 변수에 할당하거나, 결과에 대해서 추가적인 작업을 수행할 때 사용합니다!
		person.let {
        println("-------------------------------")
        println(it.name)
        it.name = "지환노"
        println(it.name)
        it // -> 이런식으로 scope function이 종료될 때 객체를 넘길 수도 있다!!
    }
    println(person.name) // scope function 안에서 값을 변경하면 적용된다!

적절한 때, 적절한 사용법

여러가지 Scope Function들의 권장 사용법을 알아봅시다!

let

  • context Object: it
  • Return Value: Lambda result
  • 객체 결과값에 하나 이상의 함수를 호출하는 경우 사용합니다.
val str: String? = "Hello"   
val length = str?.let { 
    println("let() called on $it")        
    processNonNullString(it)      // OK: 'it' is not null inside '?.let { }'
    it.length
}

with

  • Context Object: this
  • Return Value: Lambda Result
  • 이미 생성된 Context Object 객체를 인자로 받아서 사용하는 것이 효율적일 때 사용합니다.
  • with는 “이 객체를 사용하여 다음을 수행합니다”라고 읽을 수 있습니다!
val numbers = mutableListOf("one", "two", "three")
with(numbers) {
    println("'with' is called with argument $this")
    println("It contains $size elements")
}

run

  • Context Object: this
  • Return Value: Lambda Result
  • with과 비슷하지만, Context Object의 확장 기능으로 let을 호출합니다!
  • 개체 초기화와 반환 값 계산이 모두 포함되어 있을 때 유용합니다!
val service = MultiportService("https://example.kotlinlang.org", 80)

val result = service.run { // 요기에 null check도 가능하기 때문에 유용하다! service?.run
    port = 8080
    query(prepareRequest() + " to port $port")
}

apply

  • Context Object: this
  • Return Value: Context Object
  • 주로 receiver object의 개체 구성을 위해 사용합니다!
val adam = Person("Adam").apply {
    age = 32
    city = "London"        
}
println(adam)

also

  • Context Object: it
  • Return Value: Context Object
  • 속성이나 기능이 아닌 object의 참조가 필요한 작업이나 외부 범위에서 이 참조를 숨기고 싶지 않은경우 사용합니다!
val numbers = mutableListOf("one", "two", "three")
numbers
    .also { println("The list elements before adding new one: $it") } // 이렇게 log 찍기 같이 하면 좋다!
    .add("four")

총정리

FuctionContext ObjectReturn Value
letitLambda Result
runthisLambda Result
withthisLambda Result
applythisContext Object
alsoitContext Object
profile
기초가 단단한 프로그래머 -ing
post-custom-banner

0개의 댓글