반응형
[루아스크립트/프로그래밍]루아(LUA)Thread 에 대하여



thread 가 무엇인지 잘 모르시는 , 이해가 잘 않되시는분들을 위하여 thread에 대하여 잠깐 적고 넘어가겠습니다.


윈도우즈에서 하나의 프로그램을 실행하면 하나(때에 따라서 하나이상)의 프로세스를 만듭니다. 이 프로세스는 CPU가 아닙니다. 실행 하나라고 보시면 됩니다.

어떤 프로세스가 CPU를 점유하게 되면 다른 프로세스는 멈추게 됩니다.

쉽게 생각하여 무한 루프를 돌리는 코드가 돌고 있다고 생각해보면, 이 무한루프는 컴퓨터의 CPU자원을 혼자 사용하게 됩니다

그러므로 다른 프로세스는 멈추어 있어야 합니다. 컴퓨터가 아무리 성능이 좋아도 하나의 프로세스를 돌리면 다른 프로세스는 순간적으로 멈추어야 합니다.

 

그러면, 여러 프로세스가 동시에 같이 돌아야 하는 상황에서는 어떨까요? 솔직히 이는 불가능 합니다. 동시라는 것은 과학적 물리적 시간에서 정확한 동시여야 하지만, 우리는 컴퓨터 프로그램에서 동시에 라고 하면 해당 컴퓨터를 운영하는 사람이 인지못하는 범위에서 약간의 시간을 주고 조금조금씩 수행하는 것을 의미 합니다.

 

우리가 벽돌로 두개의 탑을 쌓는다고 생각해보죠. 물론 두손으로 동시에 벽돌 하나씩 양손에 쥐고 쌓으면 됩니다. 그러나 컴퓨터는 손이 하나입니다. 즉 손이 하나라고 생각해보죠. 그러면 한번에 벽돌 하나만 집어 두 탑중 한곳에 쌓아야 합니다.

간단하게 하기 위하여 두개의 탑을 1 과 2라고 생각해보조.

한번 벽돌을 집어 탑 1 에 올립니다. 다음번 벽돌을 집어 탑2에 올립니다. 다시 벽돌을 집어 탑 1에 올립니다.

이러한 과정을 계속 하다 보면 탑1 과 탑2 가 동시에 올라가는 것을 경험할 수 있습니다.

어느 탑을 우선시 하느냐에 따라 탑이 동시에 올라가도 그 속도는 차이가 있을 수 있습니다만. 어쨌든 동시에라는 것은 이러한 약간의 시간차를 두면서 거의 동시에 올라가는 것을 의미 합니다.

 

우리가 벽돌을 손으로 집어 탑에 올리는 동작을 컴퓨터에서는 프로세스 라고 합니다. 이러한 프로세스를 두개의 탑에 쌓거나

아니면 두개의 프로세스를 만들어 탑을 쌓는것이 우리가 말하는 thread 입니다.

 

일반적인 프로세스는 한번 프로세스에 들어가면 idle상태(대기상태) 가 될때까지 멈추지 못합니다. 멈춘다면 컴퓨터가 멈추는, 흔히 "프로그램이 죽었다, 다운됬다" 하는 상황이 되는 것 입니다. 살아 있는 프로세스는 계속 도는 것입니다. 설령 그 프로세스가 idle(대기 상태)에 있어도 말입니다.

 

이러한 일반적인 프로세스는 스레드가 아닙니다.

동시에 돌아가는 프로세스가 필요합니다.

어떤 프로세스가 진행, 즉 자신의 고유한 일을 하다가 어느순간 잠시 멈추어 CPU 점유를 풀어주고 다른 프로세스에게 넘겨 주는 작업이 있고, 다시 다른 프로세스가 멈추어 있을때 자신이 멈추었던 것을 이어서 계속 진행할 수 있는 프로세스가 필요합니다.

이러한 프로세스를 스레드(Thread) 또는 스레드 프로세스라고 합니다.

다른말로는 Coroutine 이라고도 합니다.

 

추후 설명하겠지만, 루아에서는 thread라기 보다는 coroutine 이라는 말이 더 적합한 형태 입니다.

루아는 가상 머신입니다. 이러한 가상머신에서 스레드같이 돌도록 하는 것을 coroutine이라는 것으로 처리하고 있습니다.

 

스레드는 다음과 같은 동작을 할수 있는 프로세스 입니다.

 

  1. 스레드의 생성     -- create
  2. 스레드의 실행     -- execute
  3. 스레드의 정지     -- suspend, yielding
  4. 스레드의 재실행  -- resume
  5. 스레드의 종료     -- terminate / dead

일반적인 프로세스는 생성-실행-종료  의 단계만 있습니다. 그러나 스레드 프로세스는 정지 및 재실행 , 즉 suspending, resume 이라는 상태를 더 가지고 있습니다.

이를 이용하여 여러가지의 일을 동시에 처리하는 능력을 부여하는 것이죠.

반응형

[루아스크립트/프로그래밍]루아(LUA)루아의 print 함수에 대하여 print 함수를 잠시 설명하겠습니다.

print 는 루아엔진에서 기본으로 제공하는 함수로 어떠한 값 또는 객체(변수)의 값을 화면에 출력해주는 기능을 수행 합니다.

기본적으로 print 함수는 stdout 으로 출력합니다. 그러나 LuaWin 에서는 이를 redirection 하여 프로그램의 아래에 있는

Consol 부분에 출력하게 되어 있습니다. 흔히 루아 코딩에 있어서 디버깅용, 내용 확인용으로 사용합니다.

 

print(2)     -- 숫자 2를 출력 합니다.

2

 

print("hello")  -- 문자열 "hello" 를 화면에 출력 합니다.

hello

 

print 문은 그 스스로 CR/LF 를 마지막으로 출력 합니다. 그러므로 print 문장은 다음 print 문장에 대하여 cr/lf 로 라인을 갱신하게 됩니다.

 

print 문이 취하는 인수의 갯수는 정해지지 않았습니다.

 

문법은

 

     print ([arg1,arg2,.....])

 

print 문은 입력되는 각 인수를 tab 으로 구분하여 화면에 출력 합니다. 즉

 

print (1,2,3)

 

이라 하면

화면에

 

1[tab]2[tab]3[cr/lf]

 

가 되겠죠.  화면에는    1    2    3    이렇게 나옵니다.

 

인수가 없는 print 문은??

print()

하면 그냥 한줄 생기는 것 입니다.

 

print(1)

print()

print(2)

 

1

[한줄추가]

2

 

이렇게 되겠죠.

 

print문은 흔히 자신의 코드를 확인하거나 디버깅, 검사 하는 용도로 사용합니다.


 

print 는 C/C++ 에서의 printf 함수가 아닙니다. 그러므로 변환 문자형태로 사용할 수 없습니다.

printf 와 같은 것을 찾는다면 루아의 string.format 을 참고하시기 바랍니다.


반응형

루아에서 사용하는 8가지의 type 에 대해서 알아 보겠습니다.

  1. number
  2. string
  3. boolean
  4. table
  5. function
  6. nil
  7. userdata
  8. thread

 

Numbers

루아는 사칙연산(더하기/빼기/곱하기/나누기)에 적용하는 숫자를 제공 합니다.

 

print(2+2)

4

 

print(2-7)

-5

 

print(7*8)

56

 

print(7/8)

0.875

 

주의 할 점은 루아에서의 숫자는 정수가 없습니다. 즉 정수 같지만, 실수로 처리 합니다.

즉 정수든 실수든 모두 그냥 number 입니다.

 

Number 는 = (대입 연산자) 에 의하여 변수에 대입될 수 있습니다.

 

x = 7

print(x)

 

7

 

 

변수는 할당 될때 생성 됩니다.

c/c++ 에서는 변수가 할당될때는 여러 부분에서 있습니다. 컴파일시/로딩시/실행중 등등..

그러나 루아에서는 변수의 선언이 없습니다. 또한 컴파일러가 아니기에

변수는 변수에 어떠한 값이 할당될때 생성이 됩니다.

 

x = 10   -- 이때 변수 x 가 할당 됩니다. 숫자로

x = "aaaa"  -- 이때 변수 x 가 다시 할당 됩니다. 문자열로

 

 

Strings

루아는 문자열(텍스트 형)을 지원 합니다.

 

print("hello")

 

hello

 

문자열 역시 변수에 할당될 수 있습니다.

 

who = "Lua user"

print(who)

 

Lua user

 

 

문자열은 .. 연산자에 의하여 합칠 수 있습니다.

who = "Lua user"

print("hello "..who)

 

hello Lua user

 

.. 연산자 역시 연산에 사용됩니다.

 

message = "hello " .. who

print(message)

 

hello Lua user

루아에서는 문자열에 + 연산자를 사용할 수 없습니다.

message = "hello " + who   -- 불가능 합니다.

 

Boolean

boolean 은 true 또는 false 를 값을 가질 수 있습니다. 즉 true 아니면 false 여야 합니다.

b = true
print(b)

 

true

 

b = not true

print(b)

 

false

 

not 연산자는 true 를 false 로, 반대로 false를 true 로 바꾸는 연산자 입니다.

 

boolean 은 논리적인 연산 (논리 연산자) 에 의하여 만들어 질 수 있습니다. 즉 논리 연산자의 결과는 boolean 입니다.

 

print(1==0)

 

false

 

print(1==1)

 

true

Tables

루아는 일반적인 목적의 집합형 데이터를 제공하며 이를 table 이라 합니다. c/c++ 의 struct (구조체) 라 생각하시면 되는데

실제적으로는 이보다 더욱 유연합니다.

 

집합형 데이터는 흔히 list, set,array,associative array 등에 사용합니다.

루아에서의 테이블은 이렇게 집합형 데이터를 처리할 수 있는 단 하나의 타입 입니다.

 

테이블의 생성

테이블은 {} 에 의하여 생성할 수 있습니다.

 

t = {}   -- 비어있는 하나의 테이블을 만듭니다.

 

테이블 자체를 print 하면 그 type 과 주소가 나옵니다.

t = {}
print(t)

 

table: 01429420
* 참고: table: 뒤의 숫자는 다를 수 있습니다.

테이블은 생성 당시 object 들을 설정하여 생성할 수 있습니다.

 

t = { value = 123, text = "hello"}

print(t.value)

print(t.text)

123
hello

테이블은 또다른 테이블을 포함할 수 있습니다.

y = { const={ name="Pi", value=3.1415927 }, const2={ name="light speed", value=3e8 } }
print(y.const.name)
print(y.const2.value)

 

Pi
300000000

 

Functions

루아에서 함수는 number 또는 string 과 같이 변수에 할당되어 집니다. 함수는 function 이라는 키워드에 의하여 생성 됩니다.

function foo() print("hello") end     -- 함수 선언

foo() -- 함수 호출

print(foo)

 

결과

hello
function: 014308F8

함수의 선언은

function 함수명([인수1,인수2,...])

-- 함수 내부

end

함수의 호출은 함수명에 () 를 붙여 호출 합니다.

함수명([인수1,인수2,...])

 

함수도 변수입니다. 그러므로 다음이 가능 합니다.

 

function foo() print("hello") end     -- 함수 선언

myfoo = foo

myfoo() -- 함수 호출

 

결과

hello

nil values

nil 은 참으로 특이한 값 입니다. c/c++ 을 아시는 분들이 혼동하기 쉽습니다. 결론적으로 nil 은 아무것도 아닙니다.

nil 은 c/c++ 의 null  이 아닙니다. c/c++ 의 null 은 0 이죠.. 그러나 루아의 nil 은 0 이 아닙니다. 그냥 nil 입니다.

 

x = 2.5
print(x)
x = nil
print(x)


결과

2.5
nil

nil 은 비교 연산에 사용할 수 있습니다.

 

print(x == nil)
x = 7
print(x == nil)
print(x)

 

결과

true
false
7

할당되지 않은 변수는 nil 입니다.

 

Userdata

userdata 는 기본 루아만으로 사용될수 없습니다. 이는 루아엔진 자체가 다른 어플리케이션에 내제되어(embeded)

C/C++ 과 연동하여 작성될때 사용 됩니다.  추후 설명을 하도록 하겠습니다.

 

Thread

Thread 역시 추후 설명 도록 하겠습니다.

 


반응형

Linked List, 참으로 필요한 것이죠.

그러나 lua 코딩을 하다보면 별 필요는 없습니다.

그 이유는 루아를 사용하여 그렇게 큰 데이터 리스트를 만들 이유가 많지 않고 또한 table 자체를 사용하면

제한 없이 정보를 보관할 수 있기 때문입니다.

 

하지만, 이론은 알고 넣어가야죠..

 

루아에서 Linked List 의 구현은 매우 쉽습니다. 그 이유는 루아의 table 이 dynamic entity (동적 요소??) 를 다루고 있기 때문이죠. 배열과 같이 정적인 메모리를 잡아서 사용하는 것이 아니라는 것이죠.

 

흔히 linked list 는 next 와 value 가 있습니다. next 는 해당 요소의 뒤에 따라오는 요소이고 value는 해당 요소에 저장하는 값이 되겠죠.

 

일단 list 는 root 가 있어야 합니다.

 

list = nil

 

이제 리스트의 가장 앞에 값 v 를 추가하는 것을 생각해 봅시다.

 

list = {next=list, value = v}

 

위와 같이 하면 list.next 가 있을 것이고, list.value 가 있을 것입니다.

list.next 는 추가되기 전의 가장 마지막의 위치가 되겠죠.

 

이렇게 계속 넣다보면 리스트의 구조를 가지게 됩니다. 마지막에 들어간 것이 물론 root 가 되어지는 것이니,

reverse list 라고나 할까요?

 

이제 이러한 list 를 순회해 봅시다. 여기서 순회란 리스트의 모든 요소를 한번 훓어서 본다 라고 생각하시면 됩니다.

iterator 에 대해서 살펴본적이 있습니다. 그와 유사한 개념 입니다.

 

    local l = list
    while l do
      print(l.value)
      l = l.next
    end

 

이들을 합쳐서 다음과 같이 테스트 해 봅니다.

 

list = nil

list = {next=list, value=10}
list = {next=list, value=20}

 

local l = list
   while l do
      print(l.value)
      l = l.next
   end

 

 

결과

20
10

앞서 말했듯이 뒤에 추가된것이 먼저 나오게 되었습니다. reverse 된 리스트라 생각하시면 됩니다.

이러한 응용에 의하여 순방향 리스트도 쉽게 구현이 가능합니다.

반응형

루아의 테이블의 활용은 막힘이 없습니다.

앞서 우리는 테이블을 이용하여 배열을 만들어 보는 것을 알아 보았습니다.

이제 2차원 배열을 알아보도록 하겠습니다.

 

    mt = {}          -- create the matrix
    for i=1,N do
      mt[i] = {}     -- create a new row
      for j=1,M do
        mt[i][j] = 0
      end
    end

위와 같이 할 경우, 물론 N 과 M 은 그 값이 미리 선언이 되어 있어야 겠지요, M*N 의 2차원 배열이 만들어 집니다.

이는 테이블의 각 요소를 테이블로 정하는 방법으로 구현한 것 입니다.

즉 mt 에 들어가는 것은 다른 배열의 row 로 사용할 또 다른 배열인 것 입니다.

 

위와 같은 경우 꼭 집어서 M*N 행이 아닐 수 있습니다. 희소행렬(Sparse matrix)의 형태가 되겠죠.

M*N 행렬이면  1열의 크기와 2열의 크기가 같아야 되지만 위의 경우 각 열이 또다른 table 이기 때문이고, table은 그 특성상

각각의 크기를 가질 수 있기 때문에 희소행렬로 보아야 할 것 입니다.

 

다음과 같은 것을 살펴봅시다.

 

    mt = {}          -- create the matrix
    for i=1,N do
      for j=1,M do
        mt[i*M + j] = 0
      end
    end


이는 전체적으로는 테이블이 하나만 생성 됩니다. 즉 1차원적인 테이블을 i , j 행렬의 계산에 의하여 2차원화 된 형상 입니다.

앞의 것 보다 사용하기는 다소 불편할지는 몰라도 M*N 행렬을 정확히 처리함은 의심의 여지가 없습니다.

 

아무튼 루아의 table을 이용한 다차원 행렬은 sparse matrix 에 적합한 구조를 제공하고 있습니다.

반응형

루아에서 배열 (Array) 은 어떻게 사용하는지를 알아 보겠습니다.

 

이미 lua table 의 사용법을 아시는 분은 이미 알고 있는 내용 입니다.

 

    a = {}    -- new array
    for i=1, 1000 do
      a[i] = 0
    end

위의 코드는 a 라는 것은 table 로 만들 어지게 됩니다 (여기서는 array 라고 여김)

a 라는 테이블에 키를 1 부터 1000 까지 바꾸면서 0의 값을 설정하는 코드 입니다.

 

table 은 대괄호 [ ] 에 의하여 key 인덱싱 될 수 있습니다. 여기서 key 인덱싱은 특정한 메모리 위치는 아닙니다.

즉 c 에서의 배열과 다릅니다.

 

그러므로 다음과 같은것이 가능 합니다.

 

a = {}

a[-1] = 20

 

print(a[-1])

 

즉 [] 안에 들어가는 것은 배열적인 인덱스가 아니라 그냥 어떤 데이터를 보관하는 장소에 대한 키 값으로 사용되는 것 입니다.

 

 

    -- creates an array with indices from -5 to 5
    a = {}
    for i=-5, 5 do
      a[i] = 0
    end

배열은 다음과 같이 초기화 할 수 도 있습니다.

 루아스크립트/루아/웹/웹프로그래밍/Lua

squares = {1, 4, 9, 16, 25, 36, 49, 64, 81}

이는

 

square[1] = 1

square[2] = 4

square[3] = 9

square[4] = 16

square[5] = 25

square[6] = 36

square[7] = 49

square[8] = 64

square[9] = 81

 

과 같은 뜻 입니다. 즉 인덱스가 1 부터 순차적으로 1씩 증가하면서 보관되게 되는 것 입니다.


반응형

for 문에 사용할 iterator 함수를 사용자가 직접 만들 수 있습니다.

 

다음의 내용은 lua-users wiki 에 있는 사용자 iterator 함수의 pseudo-code 입니다.

 

-- Equivalent to "for var1, ···, varn in explist do block end"
do
  local iterator, state, var1 = explist
  local var2, ... , varn
  while true do
    var1, ..., varn = iterator(state, var1)
    if var1 == nil then break end
      -- for block code
  end
end

 

좀 어려우니 예제를 살펴봅시다.

 루아스크립트,web,프로그래밍,웹프로그래밍,웹

function square(state,n) if n<state then n=n+1 return n,n*n end end
for i,n in square,5,0 do print(i,n) end

결과

1 1
2 4
3 9
4 16
5 25

위의 코드를 보면 square 라는 iterator 용으로 사용할 함수를 하나 만들었습니다.

이 함수를 for 문에 적용하여 iterator 역할을 수행하도록 만든 것 입니다.

 

square 함수는 state 와 n 이라는 인수를 받아서 n 이 state 보다 작을때는 n=n+1 을 해주고 return 으로

n 과 n*n 을 돌려줍니다. 2개의 값을 돌려주며, 루아에서는 함수가 한개 이상(다수의) return을 할 수 있다는 것을

알기 바랍니다. 어쨌든 위의 경우 n 과 n*n 즉 n의 제곱을 돌려주고 있습니다.

 

이 함수를 for 문의 iterator로 사용하였습니다.

 

in square,5,0 이라는 부분이 iterator 부분을 구성합니다.

 

즉 square 함수를 state = 5, n = 0 으로 초기화 하여 지속적으로 호출해 줍니다.

단 명심해야 할 것은 square 함수 자체가 지속적으로 호출되는 것이 아닙니다.

다시 말해 square 함수가 호출되면 지속적으로 함수에 인수가 전달되어야 겠죠. 그러나 이렇게 지속적으로 인수가 전달되는

것이 아닙니다. 인수는 처음에만 전달되고, 그 상태가 지속적으로 그 후에도 남게 됩니다.

 

잘보시면 square 함수의 인수에 n 이라는 변수가 있습니다. 인수로 사용한 변수이지요.

또한 for 문에 보면 i,n 에  역시 n 이라는 변수가 사용됩니다.

 

이 두게 모두 local 변수이므로 서로 다른 변수 인것을 알아야 합니다.

 

위의 코드를 분석하면 , for 문에 들어가 square 함수가 호출되어 state 및 n 에 각각 5 와 0 이 할당되어지고

square 함수의 내부계산에 의하여 return 되는 두개의 값(n,n*n) 이 각각 for 문의 i,n 에 전달되게 되어

for 문의 블럭인 print(i,n) 에서 i 와 n 즉  n,n*n 이 출력되어지고 다시 square 내부 계산이 이루어지며

조건에 맞을때 다시 n,n*n 이 return 되어 집니다.

 

조건이 만족하지 못하면 square 문은 아무것도 return 하지 않고 함수 자체가

종결이 되며 for 문의 i,n 은 nil 의 값을 받게 되어서 결국 for 문이 종료되게 되어 있습니다.

 

좀 복잡하지만, 또한 논리적으로 이해하기 힘들 수 있습니다만, 이것이 루아의 특징이라고 생각하시기 바랍니다.

 

function squares(nbvals) return square,nbvals,0 end  -- iterator,state,initial value


for i,n in squares(5) do print(i,n) end
1       1
2       4
3       9
4       16
5       25

위와 같이 squares 라는 함수를 다시 하나 더 만들어 pairs 또는 ipairs 와 같이 일반적인 iterator 함수와 같은 역할을

수행하는 함수를 만들어 사용할 수 도 있습니다.

반응형

루아는 특별히 지정하지 않는 변수는 global 변수로 지정됩니다.

그러나 함수의 인수로 사용하는 변수는 해당 함수에서만 사용되는 local 변수 입니다.

 

function f(a)

 print(a)

end


f(10)
print(a)

 

그런 이유에서 위의 코드를 실행시켜 보면

 루아스크립트,웹,프로그래밍,웹프로그래밍,web,lua

10
nil

이 나옵니다.

 

이와 마찬가지로 for 문과 같은 제어문에 사용하는 변수도 해당 for loop 에서만 사용할 수 있는 local 변수가 됩니다.

 

for i=0,5 do print(i) end

print(i)

 

결과

0
1
2
3
4
5
nil

 

위와 같은 경우에 for 문의 i는 for 문 안에서만 유효하며

for 문 밖에서는 다른 변수가 됩니다.

 

반응형

Iterator 에 대하여 알아봅시다.

 

C 의 STL 을 아시는 분은 iterator 가 무엇인지를 이해하실 것 입니다.

모르시는 분들을 위하여 잠시 여기에 소개하고자 합니다.

 

Iterator 란?

배열,리스트,큐,스텍 등등 어떠한 데이터 요소들을 다수 넣어 놓고 프로그램에서 이를 접근 운영하는 경우가 많습니다.

이러한 것을 container (컨테이너) 라고 합니다. 즉 데이터들을 담아 놓는 공간이라 생각하시면 됩니다.

 

이러한 컨테이너에 다수의 데이터들을 넣어 보관하다가 , 이 데이터들을 하나하나 순차적으로 접근할 필요가 있을때가 있습니다.

즉 데이터들을 하나하나 찾아다니며 돌아다니는 녀석이 바로 iterator (연속방문자? 정도로 해석) 라 합니다.

iterator 의 형태는 컨테이너의 자료구조에 의하여 정해집니다. 자료구조는 리스트의 구조와 트리의 구조가 있겠죠.

 

어찌됬든 이러한 방문자를 이용하여 루아의 for 문을 완성할 수 있습니다.

for 문은 일반적으로 어디서부터 어디까지 어떻게 증가하여 정해진 프로그램 블럭을 수행한다.. 라는 의미로 사용되죠.

 

여기서 iterator 를 이용하면 어디서부터 어디까지라기 보다는 해당 컨테이너(루아의 테이블)에 보관되어 있는 데이터들을 하나하나 방문하면서 for 루프를 돌리는 형태로 수행될 수 있습니다.

 

iterator를 이용하는 for loop 의 문법은 다음과 같습니다.

 

for var {, var} in explist do block end

 

여기서 explist 는 루프에 들어가기 전에 평가하는 함수 입니다. 이를 iterator function 이라 합니다.

 

다음의 함수들이 루아 테이블에서 iterator function 으로 사용되어 집니다.

 

pairs(table)

 

pairs() iterator 함수는 주어진 테이블의 key-value 쌍을 모두 처리 합니다.

인덱스에 의한 순차적인 테이블 뿐만 아니라 그렇지 않은 모든 key-value 쌍을 처리 하는 것 입니다.

 

for key,value in pairs(t) do print(key,value) end
3       10
1       3
4       17
2       7
pi      3.14159
banana  yellow

 

 

위와 같이 table t 에 있는 모든 key-value 쌍을 처리하며 , key 에 의한 순차적인 순서(order) 를 지키지 않습니다.

 루아스크립트,프로그래밍,웹,웹프로그래밍

 

ipairs(table)

 

이 함수는 pairs 함수와는 다르게 순차적인 key order 를 처리 합니다. 즉 순차적이지 않은 key 에 대해서는 처리하지 않습니다.

 

for index,value in ipairs(t) do print(index,value) end
1       3
2       7
3       10
4       17

 

위에서와 같이 table t 에 있는 key-value 쌍중에 순차적인 인덱스로 이루어진 데이터들에 대해서만 순차적으로 처리하게 됩니다.

 

순차적이면서 순차적이지 않은 모든 key-value에 대하여 처리하고자 한다면 다음과 같이 사용하면 됩니다.

 

for key,value in next,t,nil do print(key,value) end


1       3
2       7
3       10
4       17
pi      3.14159
banana  yellow

이러한 형태는 next 함수를 사용하는 것 입니다. 위의 문장은 next 함수로 t 를 처리하며 nil 이 될때까지 진행 합니다.


반응형

루아에서의 for 문은 크게 두가지의 형태로 생각해 볼수 있습니다.

  1. 인덱스 증감에 의한 데이터 접근 (Numeric progression)  -- numeric for 문이라 함
  2. Iterators (반복자) 에의한 데이터 접근 (Iterators)            -- generic for 문이라 함

Numeric Progression

 

Numeric progression 에 의한 접근은 다음과 같은 문법을 갖습니다.

 

for variable = from_exp , to_exp [, step_exp] do block end

이러한 형태에서는

variable 이 for 문을 들어가기전에 from_exp 에 의하여 초기화 되며, to_exp 가 될때까지 진행 하며

block 문이 수행 됩니다.

각 block 문이 수행된 후 step_exp 만큼 variable 은 중감하게 되어 to_exp 까지 도달하게 됩니다.

만약 step_exp 가 생략될 경우 1로 간주 하게 되어 1씩 증가하게 되는 것 입니다.

 

for i = 1,3 do print(i) end

 

결과

1
2
3

 

for i = 3,1 do print(i) end

 

와 같이 하면 for문은 돌지 않습니다.

c 에서 생각한다면 무한루프의 소지가 있습니다만, 루아에서는 그렇지 않습니다.

 

for i = 3,1,-1 do print(i) end

 

결과

3
2
1

 

 

for i=1,0,-0.25 do print(i) end

 

결과

1
0.75
0.5
0.25
0

 

와 같이 증감을 실수를 사용할 수 도 있습니다.

 

위의 예들에서 순차적 증가값으로 i 라는 변수를 사용하게 됩니다. 이 변수는 local 로 변수입니다.

for 문에 사용된 증감 변수는 local 이라 지정하지 않아도 자동적으로 local 변수로 처리 됩니다.

 

for i=1,0,-0.25 do print(i) end

print(i)

 

를 수행하면

1
0.75
0.5
0.25
0
nil

와 같이 i 값이 nil 이 됩니다. 즉 for 문의 i 와 print(i) 의 i 가 다르다는 것이죠.

 

 

for i = e1,e2,e3 do myFunction(i) end

와 같이 변수를 사용할 수도 있습니다.

반응형

좀 의아해 할 수 있습니다만, 다음의 예를 살펴보죠.

 

t = { [function(x) print(x) end] = "foo" }
for key,value in pairs(t) do key(value) end


 

위에서 보면 t 라는 테이블은 function(x) print(x) end 라는 함수 즉  x 를 인수로 받아 이를 consol 에 출력하는 함수 입니다.

이 함수 자체가 키가 됩니다. 그러면서 이 키에 설정된 값이 "foo" 입니다.

 

그러면 for 문에 의해서

 

일단

 

key,value in pairs(t)

 

에 의하여 테이블 t 에 있는 key 와 value 를 가져오게 되겠죠.

여기서 key 는 결국 앞어서 말한 함수가 됩니다. 그리고 value 는 "foo" 라는 값이 되겠죠.

 

do key(value)

 

에 의하여 결국 key 라는 함수 , 즉 앞에 키로 넣은 함수 에 value 를 인수로 호출한 것이 됩니다.

 

function(value) 이렇게 되겠죠.

 

결국 value 가 화면에 찍히게 됩니다.

 

과연 이런것을 어디에 사용할 까요?

 

다수의 값이 있고 그 값을 처리하는 함수가 각각 따로 있다고 생각해보죠.

이들을 하나의 테이블에 보관하여 관리할 수가 있겠죠.

 

이런정도의 용도,, 약간의 OOP 적인 성격을 갖는 용도로 활용할 수 있지 않을까 합니다.

반응형

복잡하게 생각하지 말고 다음과 같은 예를 들어 보겠습니다.

 

 t = { apple=5 }
 a = "apple"
 b = "apple"
 print(t.apple, t[a], t[b])

 

결과는

5 5 5

위에서와 같이

t 라는 테이블은 apple라는 키에 5 가 설정된 테이블입니다.

 

이에 대한 접근은

 

t.apple

 

로 접근할 수 있으며,

 

또한 문자열 "apple" 이라는 것으로도 접근할 수 있다는 것 입니다.

 

이러한 기능이 별 필요 없거나 단순하다고 생각할 수 있습니다만,

 

이렇게 생각해보면 매우 유용합니다.

 

c/c++ 같은 고급 언어에서는 변수와 변수와 같은 이름의 문자열은 서로 연결할 수가 없습니다.

 

즉 c 에서

int apple;

string s = "apple";

 

이라는 것이 있을때

s 와 apple 사이의 관계는 특별히 매칭함수를 만들어 주지 않는이상 연결이 어렵습니다.

 

그러나 루아에서는 이렇게 특정 변수를 데이터인 문자열로 접근할 수 있도록 하는 기능을 제공하는 것 입니다.

반응형

루아 테이블에서의 저장 영역은 키-값 (key-value)의 쌍으로 이루어 집니다.

루아는 일반적인 배열(array) 과 dictionary 간의 차이점을 갖지 않습니다.

즉 배열과 dictionary 간의 차이를 루아 테이블에서는 볼수 없다는 것이죠.

 

모든 루아의 테이블들은 실질적으로는 dictionary 와 같이 동작 합니다. 일반적으로 배열에서의 키는 정수이어야 한다는것과도

다르죠.

 

> t = { 3,6,9 }                 -- is the same as...

> t = { [1]=3, [2]=6, [3]=9 } -- is the same as...
> t = {} t[1]=3 t[2]=6 t[3]=9

이러한 의미에서 위의 3줄은 모두 같은 내용 입니다.

 

테이블의 키는 일종의 레퍼런스(reference) 입니다.

a = { [{1,2,3}]="yadda" }              -- construct a table where the element has a table key
for k,v in pairs(a) do print(k,v) end  -- display the table contents: key-value pairs
print( a[{1,2,3}])                           -- display the element value

 

위와 같은 예제서 결과는

table: 014D9150 yadda
nil

입니다.

k,v in pairs(a) 에서

k 는 테이블 a에 있는 키, v 는 해당 키로 지정된 값 입니다.

또한 a 의 키는 {1,2,3} 이라는 테이블입니다. [] 를 쒸운것은 이 테이블 자체의 주소를 키로 사용한다는 것이죠.

그러므로 k 는 table 이라는 값이 나오는 것이고 그 주소가 나오는 것 입니다.

역시 v 는 해당 키에 대한 값 "yadda" 이죠.

 

위의 값을 다음과 같이 풀어보죠.

tablekey = {1,2,3}                     -- create a table with a variable referencing it
a = { [tablekey]="yadda" }             -- construct a table using the table as a key
for k,v in pairs(a) do print(k,v) end  -- display the table elements
print(a[tablekey])                          -- retrieve a value from the table
print(tablekey)              -- the table value is the same as the key above

 

결과는

table: 014D89D0 yadda
yadda
table: 014D89D0

 

위와 같이 보시면 이해가 좀 쉬우실 겁니다.

 

반응형

Mixed table constructor , 즉 혼합형 테이블 이라 할 수 있습니다.

말로는 이해가 어렵습니다.

 

우리는 table을 이용해서 dictionary 를 구성할 수 있음을 알았습니다. dictionary 에는 키가 있고 그 키에 저장되는 값이 있습니다.

 

table.key = 값

일반적으로 dictionary 는 키의 자료형태, 즉 데이터 타입이 같은 형태(정수면 정수, 문자열이면 문자열 등등)를 사용합니다.

그러나 루아의 table은 이러한 키의 형태가 같지 않아도 됩니다.

또한 순차적이지 않아도 됩니다.

 

다음의 예를 살펴보독 하죠.

 

t = { 2,4,6, language="Lua", version="5.1" }
for k,v in pairs(t) do print(k,v) end

for i,v in ipairs(t) do print(i,v) end

결과는

1 2
2 4
3 6
language Lua
version 5.1


1 2
2 4
3 6

 

위에서
앞의 for 문에 의해서는 정수로 인덱스(순차적)된 내용과 language, version 으로 명명된 키의 값들도 나옵니다.

그러나 뒤의 for 문에 의해서는 정수로 인덱스된 순차적인 것들만 나옵니다.

이는 pairs() 와 ipairs 의 차이에 의해서 발생하는 결과 입니다. 이 두가지의 차이는 추후 다시 설명하기로 하고

일단 여기서는 하나의 table에 서로 다른 형태의 순차적이지 않은 값들을 동시에 사용할 수 있다는 것 입니다.

c 나 c++ 프로그램을 하다보면, 가끔 위의 형태를 만들기 위하여 노력할 때가 있습니다.

즉 어떠한 데이터 집단을 만들고 그 데이터 집단의 이름과 특징들을 적어놓을 공간을 만들기 위하여 구조체나 class 의

구조화된 형태를 다소 복잡하게 만들어 사용하게 됩니다.

 

이런 경우 루아의 table은 쉽게 그 형태를 구성하도록 해 줍니다.

반응형

일단 Dictionary 란 무엇인가를 알아보도록 하죠.

STL 을 아시는 분은 map 같은 것이죠.

 

Java, C# 등에서도 제공 됩니다.

 

언듯 들으면 전자사전? 정도로 생각할 수 있습니다. 의미적으로 비슷합니다.

프로그램을 만드는데 있어서 dictionary 라는것이 무엇인지 알아보도록 하죠.

 

가령 우리가 전국 지역번호(전화의) 를 참조하는 것이 필요하다고 할때,

 

지역번호는 정해져 있습니다. 즉 바뀌기 어렵죠. 다만 그 값을 사용하는것이 매우 빈번 하게 발생 합니다.

즉 어떠한 정보가 있으면 정보의 내용을 갱신하는 빈도와 , 그 정보들중 필요한 것을 찾아 사용하는 것의 방법으로

정보에 접근하는 형태가 나뉘어 집니다.

이는 우리가 영어사전이 그 내용자체는 바뀌는것이 드물며(어떤 정보는 평생 변하지 않을수도 있음) 단지 모르는 영어단어를

찾아보는 경우가 훨씬 많다는 것 입니다.

 

이러한 경우에 우리는 이러한 정보를 위의 사용에 보다 효과적으로 대처할 수 있도록 자료들을 보관하는 방법을 찾습니다.

이러한 경우에 사용하는 방법이 dictionary 입니다. 일종의 자료구조의 하나이지요.

 

루아에서 이러한 dictionary 형태를 table 을 이용하여 만들 수 있습니다.

 

아래의 정보가 있다고 생각해 봅니다.

 

서울 = 02

경기 = 031

인천 = 032

강원 = 033

부산 = 051

충남 = 041

대전 = 042

제주 = 064

 

지역번호는 더 많지만 일단 이것으로...

 

C에서 배열 또는 리스트로 위의 내용을 저장하여

만일 충남의 지역번호는? 이란 질문이 들어올때 배열을 쭉 찾아서 충남이 나올때까지 돌려 해당 값을 찾겠죠.

아니면 STL 의 map 과 같은 형태로 코딩을 할 수 있겠죠?

 

루아에서는 테이블을 이용합니다.

 

ddd = {["서울"]="02", ["경기"]="031", ["인천"]="032", ["강원"]="033", ["부산"]="051", 
      ["충남"]="041", ["대전"]="042", ["제주"]="064" }

 

print(ddd["제주"])
print(ddd["서울"])

 

이렇게 검색할 수 있다는 것 입니다.

 

여기서 table은 table[key] = 값, 형식으로 키로 사용하는 것이 문자열일 수 있고 아니면 멤버 변수일 수 있습니다.

키가 영문자일경우는 [ ] 를 사용하지 않아도 됩니다.

 

 

ddd = {seoul="02"}


print(ddd["seoul"])

 

 

또한 아래와 같이 객체의 접근형태(c 에서의 구조체 연산자)로 접근할 수도 있습니다.

ddd = {seoul="02"}


print(ddd.seoul)

 

위와 같이 table을 이용하여 dictionary 의 구조적 문법을 사용할 수 있습니다.


종합예제:


d = {s="02", k="031", i="032", g="033", b="051", 
c="041", d="042", j="064" }



print(d.c)
print(d.s)

출력값:041
02



+ Recent posts