프로그램의 덩치가 조금씩 커지면 특정한 기능은 외부파일(모듈)로 따로 분리시켜야 여러모로 효율적이다. 코로나(루아)에서 외부 모듈은 다음과 같이 사용한다. 먼저 새로운 화일을 생성해서 다음과 같이 작성한다.

┌─────────────────────────────
    local M = {}
    M.a = 10
    M.t = {x=0, y=20}
    function M.Fa()
        print("Fa() called.")
    end
    return M
└─────────────────────────────

혹은 위와 완전히 동일하지만 다음과 같이 작성할 수도 있다.

┌─────────────────────────────
    local M = {
    a = 10,
    t = {x=0, y=20},
    Fa = function()
        print("Fa() called.")
    end,
}
    return M
└─────────────────────────────

이 화일에서 하는 일은 테이블 M을 생성한 후 변수 a, t, Fa를 채워서 반환하는 것이다.
이것을 살펴보면 입력변수가 없는 일반적인 함수의 내부와 동일한 구조이고 위아래에function() ... end가 없는 함수의 본체와 모양이 같다는 것을 알 수 있다.
이제 이것을 "lib1.lua" 화일로 저장한 후(화일 이름은 각자 다를 것이다) 현재 화일 내에서 (예를 들어서 main.lua)

-------------------------------------------------------------------------
local libA = require "lib1"
-------------------------------------------------------------------------


과 같이 읽어들이면 "lib1.lua" 화일에서 반환된 테이블 M이 libA변수에 올라온다. 이제 libA변수로 "lib1.lua"모듈의 변수 a, t, Fa등을 다음과 같이 읽고 쓸 수 있다.

-------------------------------------------------------------------------
local b = libA.a -- 변수 읽기
libA.t.x = 100 -- 변수 쓰기
libA.Fa() -- 함수 호출
-------------------------------------------------------------------------

이렇게 기본적인 사용법은 굉장히 간단한데 한 가지 오해할 수 있는 사항이 있다. 예를 들어서 main.lua 가 다음과 같이 작성되어 있다고 하자.

┌─────────────────────────────
    local libA = require "lib1"
    print("libA.t.x="..libA.t.x)
    libA.t.x=100

    local libB = require "lib1"
    print("libB.t.x="..libB.t.x)
└─────────────────────────────

이것의 두 번째 print()문의 출력이 무엇일지 짐작해 보자. 필자는 처음에는 당연히 0일 줄 알았는데 이것은 새로운 테이블 M을 생성해서 libB에 할당하는 것으로 오해하기 쉽기 때문이다. 그런데 실제 실행결과는 100이 찍힌다. 즉 libA의 변경결과가 libB에 반영이 되는 것이다.
이것으로 짐작할 수 있을텐데 lua에서는 같은 외부모듈을 다시 읽어들일 때는 이 전에(맨 처음에) 메모리에 올라온 내용을 참조한다. 즉 libB는 새로 생성되지 않고 이전에 올라온 libA와 완전히 같은 곳을 참조하고 있다. 이후로 몇 번을 반복해서 불러오거나 다른 화일에서 같은 모듈을 읽어 올 때도 맨 처음에 생성된 테이블을 참조한다.

심지어 libA를 삭제해도 모듈은 여전히 메모리에 남아 있다는 것도 유의해야 한다.

┌─────────────────────────────
    local libA = require "lib1"
    print("libA.t.x="..libA.t.x)
    libA.t.x=100

    libA = nil
    collectgarbage("collect") -- libA 완전히 삭제
    local libB = require "lib1"
    print("libB.t.x="..libB.t.x) -- 여전히 출력은 100이다.
└─────────────────────────────

이것을 이용하면 프로젝트 전반에서 공통적으로 참조해야하는 변수를 글로벌 변수로 사용하지 않고 하나의 외부 모듈에 모아놓고 관리할 수도 있다.


Posted by 살레시오
,