Vintage appMaker의 Tech Blog

[kotlin] apply에서 람다 사용시 범위(scope) 본문

Source code or Tip/Android(Java, Kotlin)

[kotlin] apply에서 람다 사용시 범위(scope)

VintageappMaker 2021. 6. 12. 10:24

Android에서 코틀린으로 개발하다보면 closure와 람다는 자신의 의지와 관계없이

많이 사용하게 된다. 그러다보니 어느 순간부터 람다식과 closure를 활용한 코딩스타일에 익숙하게 되는데, 

그 때 많이 실수하는 것이 람다식의 scope이다.

 

(1)
{
    람다를받는함수( {람다식} )
}

(2)
람다를받는함수(){
    {람다식}
}

 

일반적으로 람다식의 범위는 (1)의 영역인 [람다를받는함수]를 호출하는 영역이다. 

그러나 람다를받는함수가 클래스내의 함수(메소드)이고 그 객체를 생성하고 apply를 사용하게 된다면 복잡한 상황이 발생한다.

inerCls와 outerCls의 리소스를 동시에 사용할 수 있다. 

2.번의 경우, 호출부(innerCls)와 실행부(outerCls) 범위의 리소스를 모두 액세스 가능하게 된다. 

 

일반적으로는 호출부의 리소스를 실행부에서 사용하려면 3.번과 같이 한다. 그러나 객체를 생성하고 apply에서 사용시에는 두 영역의 리소스를 동시에 사용할 수 있다. 문제는 2.번과 같이 양쪽에 같은 변수명이나 함수가 존재할 때인데, 이때는 기본적으로 호출부(innerCls) 영역을 선택하게된다. 

 

 

 

 

fun main() {
    outerCls().apply{
        doTest()
    }
}

class outerCls {
    var name = "base"
    var age  = 100 / 2 + 2
    fun outerFunc() = println ("outer Func")
    fun doTest(){
        innerCls().apply{
            // 1. 넘겨지는 람다(doFunction)의 스코프는 outerCls
            doFunction{
                // outerCls의 age
                println (age)
                outerFunc()
            }

            // 2. 넘겨지는 람다(doFunction)의 스코프는 outerCls 이지만
            // doFunction을 호출하는 영역은 innerCls이다.
            // 그래서 변수명이 innerCls에서 같은 것이 존재한다면
            // innerCls의 변수를 기본적으로 사용하게 된다.
            doFunction{
                // innerCls의 name
                println (name)
                // outerCls의 name
                println (this@outerCls.name)

                // innerCls의 innerFunc()
                innerFunc()
            }

            // 3. 람다(doFunction)에서 innerCls의 자원을 사용하고자 한다면
            // innerCls에서 파라메터로 자신을 넘겨주면 된다.
            // (*) apply 안에서 사용한다면 doFunction2와 같이
            // 할 필요없이 2.번처럼 하면된다.
            doFunction2{
                inner ->
                inner.innerFunc()
            }

        }
    }

}

class innerCls{
    var name : String = "inner"
    fun innerFunc() = println("innerCls Func")
    fun doFunction (fn: () -> Unit){
        fn()
    }

    fun doFunction2 (fn: ( c: innerCls ) -> Unit){
        fn(this)
    }
}
Comments