Scope function

최희창·2022년 8월 29일
0

Kotlin

목록 보기
11/13

Introduction

  • 코틀린 표준 라이브러리에는 Scope 함수를 지원합니다. Scope 함수 이름에서 알 수 있듯이 함수를 호출하면 일시적인 Scope이 생기게 된다.
  • 이 Scope 안에서는 전달된 객체에 대해 it 또는 this라는 Context Object를 통해서 접근하게 됩니다.

특징

  • Scope 함수 사이에는 2 가지 주요 차이점이 있습니다.
  1. Context Object를 참조하는 방법(this, it)
  2. Return value

Context Ojbect: this or it

  • Scope Function 람다식 내에서 Context Object는 실제 객체명 대신, it 또는 this로 접근하게 됩니다.
class Person (var name: String, var age: Int)

fun main() {
    val person = Person("홍길동", 30)
    
    //this로 참조
    person.run {
          println("이름 : ${name}") //this.name과 동일
    }
    
    //it로 참조
    person.let {
          println("이름 : ${it.name}")
    }
}

this

  • run, with, apply는 Context Object를 this로 참조합니다.
  • 동일한 이름의 변수가 있을 경우 구별할 수가 없기 때문에, 가급적이면 Context Object에 대해서는 this를 붙여서 사용하는 것이 좋습니다.
class Person (var name: String, var age: Int)

fun main() {
    val person = Person("홍길동", 30)
    
    //this로 참조
    person.run {
          println("이름 : ${this.name}")
    }
}

it

  • let, also는 Context Object를 it로 참조합니다.
class Person (var name: String, var age: Int)

fun main() {
    val person = Person("홍길동", 30)
    
    //it로 참조
    person.let {
          println("이름 : ${it.name}")
    }
    //전달 인자명 지정해서 참조
    person.let { value ->
          println("이름 : ${value.name}")
    }
}

Return value

  • apply, also는 Context Object를 반환
  • let, run, with는 람다식 결과를 반환

Context Object

  • apply, also의 반환 값은 Context Object 객체 자체입니다. 그렇기 때문에, 체인 형식으로 계속 호출이 가능합니다.
  • 함수의 return 문에도 사용할 수 있습니다.
val numberList = mutableListOf<Double>()
numberList.also { println("Populating the list") }
    .apply {
        add(2.71)
        add(3.14)
        add(1.0)
    }
    .also { println("Sorting the list") }
    .sort()
    
fun getRandomInt(): Int {
  return Random.nextInt(100).also {
     writeToLog("getRandomInt() generated value $it")
  }

val i = getRandomInt()

Lambda Result

  • let, run, with는 람다식 결과를 반환합니다. 그렇기 때문에 결과를 변수에 할당하거나, 결과에 대해 추가적인 작업 등을 수행할 때 사용할 수 있습니다.
val numbers = mutableListOf("one", "two", "three")
val addNumbersList = numbers.run { 
    add("four")
    add("five")
}

Functions

let

  • Context Object : it
  • Return Value : lambda result

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

/** let 안썼을 때 */
val numbers = mutableListOf("one", "two", "three", "four", "five")
val resultList = numbers.map { it.length }.filter { it > 3 }
println(resultList)    

/** let 사용 시 */
val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }.filter { it > 3 }.let { 
    println(it)
    // 추가적인 함수 호출 가능
} 

null이 아닌 값으로만 코드블록을 실행시키고 싶을 때 자주 사용됩니다.
null이 아닌 객체에 대해 작업을 수행하려면 안전한 호출 연산자 ?.를 let에 사용하도록 합니다.

val str: String? = "Hello"   

val length = str?.let { //안전한 호출 Safe Call
    println("let() 호출 $it")        
}
val numbers = mutableListOf("one", "two", "three", "four", "five")
val resultList = numbers.map { it.length }.filter { it > 3 }
println(resultList)  

->

val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }.filter { it > 3 }.let { 
    println(it)
    // and more function calls if needed
} 

with

  • Context Object : this
  • Return value : lambda result

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

val numbers = mutableListOf("one", "two", "three")
val firstAndLast = with(numbers) {
    "첫번째 요소는 ${first() 입니다.}," +
    "마지막 요소는 ${last() 입니다.}"
}
println(firstAndLast)

run

  • Context Object : this
  • Return Value : lambda result

with와 비슷한 역할로, 이미 생성된 Context Object 객체를 사용할 때 호출하며 with와는 전달받는 위치가 다릅니다.
앞에 Safe Call(?.)을 붙여서 null 체크까지 할 수 있어서, with 보다는 run이 더 자주 사용됩니다.

/** 기본 코드 */
val point = Point()
val width = point.x * 0.5

/** run() 사용 코드 */
val width = run {
    val point = Point()
    point.x * 0.5
}

val point = Point()
val width = point.run {
    x * 0.5
}

imageView.layoutParams.run {
    width = 400
    height = 200
}

apply

  • Context Object : this
  • Return Value : Context object

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

val person = Person("홍길동").apply {
                  age = 30
             }

also

  • Context Object : it
  • Return Value : Context object

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

val numbers = mutableListOf("one", "two", "three")
numbers
    .also { println("새 항목 추가하기 전 리스트 요소들: $it") }
    .add("four")

(참조 블로그 : https://0391kjy.tistory.com/25)

profile
heec.choi

0개의 댓글