ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Scope Functions (let, with, also, apply, fun)
    Android 2024. 3. 16. 09:06

    어떤 객체의 변수, 메소드 등을 불러올때는 scope function 을 쓰는게 편리할 때가 있다.

       Scope 내 접근방식 this Scope 내 접근 방식 it
    블록 수행 결과 반환 run, with let
    객체 자신 반환 apply also
      수신 객체 자체를 람다로 전달 수신객체를 람다의 파라미터로 전달

    뒤에 코드에 주석처리한 부분을 보면 이해가 되는데, T는 수신객체를 의미한다. 이때, 수신객체는 it으로 사용할 수 있는데 따라서 scope 내 접근 방식이 it 인 경우, 수신객체를 람다의 파라미터로 전달한다는 뜻이다. block 내부(중괄호)는 람다함수의 소스코드를 의미한다.

    1. let 함수

    중괄호 블록 안으로 객체를 it 으로 전달하고, 블록 수행 결과를 반환한다. 이때, strNum 의 자료형은 let 함수를 쓴다고 변하지 않는다. strNum 의 자료형은 Int형이 아니라 여전히 String형이다.

    fun main() {
        var strNum = "10"
        var result = strNum?.let {
            it.toInt()
        }
        println("result : ${result}") // Int 형
        println("strNum : ${strNum}") // String 형
    }
    
    // 수신객체(T)를 람다의 파라미터로 전달
    // public inline fun <T,R> T.let(block:(T) → R): R

    2. with 함수

    중괄호 블록 안으로 객체를 this 로 전달하고, 블록 수행 결과를 반환한다. 이때 scope 내에서 this 를 생략해서 편리하게 쓸 수 있다. 여전히, alphabet 은 변하지 않는다. this 를 생략해서 쓸 수 있다는 점에서 받아오는 객체는 반드시 null 이 아닐때 사용해야 한다. 참고로 subSequence(a,b) 함수는 해당 문자열의 index a 부터 index b-1 까지의 문자를 반환한다.

    fun main() {
        var alphabet = "abcd"
        with(alphabet) {
            var result = this.subSequence(0,3) // subSequence(0,3) 는 index : 0 ~ index : 2 까지 출력한다는 의미이다.
            var result2 = subSequence(0,2) // this 는 생략가능
            println("result : ${result}") // result : abc
            println("result2 : ${result2}") // result2 : ab
        }
    }
    
    // 수신객체 자체(T.()) 를 람다로 전달
    // public inline fun <T,R> with(receiver: T, block:T.() → R) : R

     

    3. also 함수

    중괄호 블록 내로 객체를 it 으로 전달하고, 결과값으로 객체를 반환한다. apply 함수와 함께 자주 사용한다.

    이때, also 함수를 사용하면 객체 자체의 정보도 변경된다.

    fun main() {
        var student = Student("참새",3)
        var student2 = student.also {
            it.age=7 // student 자체의 age 변수값도 7로 바뀜
        }
        student.displayInfo() // 이름: 참새, 나이: 7
        student2.displayInfo() // 이름: 참새, 나이: 7
    }
    
    class Student(name:String, age:Int) { // 주생성자 사용
        var name : String
        var age : Int
    
        init {
            this.name=name
            this.age=age
        }
    
        fun displayInfo() {
            println("이름: ${name}, 나이: ${age}")
        }
    }
    
    // 수신객체(T) 를 람다의 파라미터로 전달
    // public inline fun <T> T.also(block: (T) → Unit) : T

     

    4. apply 함수

    apply 함수 같은 경우 객체를 중괄호 안에서 this 로 전달하는데, this 는 생략해서 사용 가능하다. 이때, apply 함수 앞에 붙는 객체도 내용이 변경된다.

    fun main() {
        var student = Student("참새",3)
        var student2 = student.apply {
    //        this.age=10
            name="비둘기" //이때, 매개변수로 받는 this는 생략가능하다. apply 함수의 객체인 student 도 값이 변경된다.
        }
        student.displayInfo() // 이름: 비둘기, 나이: 3
        student2.displayInfo() // 이름: 비둘기, 나이: 3
    }
    
    // 수신객체 자체(T.())를 람다로 전달
    // public inline fun <T> T.apply(block: T.() → Unit): T

     

     

    글쓴이 물음표

    - this 랑 it 으로 왜 구분해서 객체를 전달받는거지?

     

    5. run 함수

    객체를 호출하지 않고 run 함수를 이용하여 작성할 수 있다.

    fun main() {
        var totalPrice = run {
            val computer = 10000
            val mouse = 5000
            computer + mouse
        }
        println("totalPrice : ${totalPrice}") // totalPrice : 15000
    }

    run 함수 내에서 this 는 생략가능한데, with 와 달리 null 체크를 수행할 수 있어 with 보다 더욱 안전하게 사용가능하다.

    fun main() {
        var student = Student("참새",5)
        student.run {
            displayInfo() // 이름: 참새, 나이: 5
        }
    }
    
    // 수신객체 자체(T.())를 람다로 전달
    // public inline fun <T,R> T.run(block: T.() → R) : R

     

     

    scope function을 중첩으로 사용할 때, 모든 수식객체를 it 으로 사용하면 문제가 발생할 수 있다. 이때는 람다식 내부를 it 대신 다른 문자를 사용하여야 한다. 

    fun main() {
        Person().also {
            it.name="비둘기"
            it.age=3
    //        val sparrow = Person().also {
    //            it.name="참새" // 누구의 it인지 모른다
    //            it.age=10
    //        }
            val sparrow = Person().also { c ->
                c.name="참새"
                c.age=10
            }
            it.child=sparrow
        }
    }
    
    data class Person(
        var name: String = "",
        var age: Int? = null,
        var child: Person? = null
    )

    'Android' 카테고리의 다른 글

    MVC, MVP, MVVM, MVI  (0) 2024.03.19
    확장함수  (0) 2024.03.18
    Pair,Triple 클래스  (0) 2024.03.15
    자료형변환, 업캐스팅, 다운캐스팅, Is 키워드  (0) 2024.03.15
    여러 복합 계산 : 후위연산자, Stack 개념 활용  (0) 2024.03.14
Designed by Tistory.