2013년 9월 12일 목요일

코로나에서 외부 모듈을 사용하는 방법 (1)

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

┌─────────────────────────────
          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이다.
└─────────────────────────────

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

댓글 없음:

댓글 쓰기