루아의 변수는 다음과 같이 8가지 데이터타입을 갖는다.


nil

부울값

숫자

문자열

테이블

함수

----------

코루틴

유저데이터


이 중에서 코루틴과 유저데이터는 코로나SDK와 별로 관련이 없으므로 제외하고 나머지 여섯 개 중 참조를 갖는 것은 함수와 테이블이다. 문자열은 참조가 아니라는 것에 유의해야 한다. 참조란 실제 데이터가 저장된 곳을 가리키는 주소이다. (사실 참조도 주소'값'이므로 루아는 다 값이라고 주장하기도 하지만 혼동의 여지가 있으므로 여기서는 참조와 값을 구분하도록 하겠다.)

따라서 만약 어떤 테이블을 함수의 입력파라메터로 넘길 때 참조가 넘어가므로 그것을 받아서 조작하면 원래의 테이블값도 바뀌게 된다.


┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓

    local function Func1(a, tA)

        a = 20

        tA.x = 20

    end


    local function Func2(tA)

        tA = {x=30}

    end


    local x, tX = 10 , {x=10}

    Func1(x, tX) -- x는 값이, tX는 참조가 넘어간다.

    print(x, tX.x) -- 10, 20 이 찍힌다.

    Func2(tX)

    print(tX.x) --20이 찍힌다.

┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛


위의 예에서 Func1()을 호출할 때 로컬 변수 x는 값이 넘어가고 테이블 tX는 참조가 넘어가므로 함수 호출 후 테이블의 필드만 값이 변경되었다. 반면에 Func2()내에서는 tA가 tX의 참조를 받기는 하지만 새로운 테이블의 참조로 초기화되었다. 따라서 이경우 tA는 넘어온 tX와는 전혀 별개의 것이 되어서 tX에는 아무런 영향을 끼치지 못한다. 그래서 맨 마지막 print()에서 20이 찍히는 것이다.


이와 마찬가지로 함수의 리턴값이 테이블이나 함수일 경우도 참조를 반환한다. 다음 예는 처음에는 조금 이해하기 힘들 수 있으나 한 번 살펴보도록 하겠다.


┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓

    local function Func1(xR)

        local x = xR or 0 -- 내부변수 x를 넘어온 값으로 초기화

        local y = 0

        local Func = function() print("x :"..x);end -- 여기서 x가 사용되었다.

        return y, Func -- y는 '값'을, Func는 '참조'를 반환

    end


    local y1, Func2 = Func1(10)

    local y2, Func3 = Func1(20)

    Func3() -- 20 이 찍힌다.

    Func2() -- 10 이 찍힌다.

┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛


함수 Func1()은 그 안에서 내부변수 y의 '값'과 내부변수 Func의 '참조'를 반환한다. 기본적으로 어떤 함수의 지역변수는 함수가 종료되면 사라진다는 것은 알고 있을 것이다. 변수 y는 함수가 종료되면 더 이상 참조되는 곳이 없으므로 GC의 타겟이 되어 사라질 것이다. 하지만 내부함수 Func는 그 참조가 호출된 곳의 Func2 변수를 통해서 계속 사용되므로 사라지지 않고 살아남게 된다. 그럼 내부변수 x는 어떨까? x변수는 Func안의 print()문에서 참조를 하고 있으므로 Func가 살아있는 한 x도 계속 살아있게 된다.


또 한가지 주의할 것은 Func2 와 Func3에서 참조하는 변수 x는 서로 별개의 것이라는 점이다. 따라서 처음 Func3()호출에는 20이 찍히고 맨 마지막 Func2() 함수를 호출하면 10이 찍힌다. 서로 '다른' 변수 x를 참조하고 있기 때문이다.


이것을 이해했다면 클래스를 구현할 때 외부에서는 접근할 수 없고 내부에서만 사용할 수 있는 private 변수/함수 를 구현하는데 응용할 수 있다.

Posted by 살레시오
,