시리즈:쉽게 배우는 프로그래밍 입문/Lua

Utolee90 (토론 | 기여)님의 2022년 6월 18일 (토) 19:28 판 (→‎사용 방법: 오타 수정)

문서의 내용이 너무 쉬워서 오늘부터 프로그래밍 할 수 있을 것 같습니다.

이 문서에는 독자적으로 연구한 내용이 들어갑니다. 다른 사람의 의견을 존중하면서 무례하지 않도록 작성해 주시고, 의견 충돌 시 토론 문서에서 토론해 주세요.
리브레 프로그래밍 시리즈
초급
프로그래밍
중급
프로그래밍
고급
프로그래밍
Python
협업

이 문서에서는 스크립트 언어로 사용하는 Lua(루아)에 대한 간단해 배워봅시다.

Lua는 어떤 언어인가?

Lua는 독립적으로 사용하기보다는 C언어 기반 프로그램에서 별도로 스크립트를 실행시키기 위한 목적으로 만든 언어입니다. 상당히 가볍지만 파이썬처럼 라이브러리가 풍부하지는 않아 범용성이 좋은 프로그래밍 언어로 평가받지는 않습니다.

여기 리브레 위키를 비롯한 미디어위키 기반의 위키들도 이 Lua라는 언어를 사용하고 있는데, 바로 Scribunto 확장기능의 모듈을 돌릴 때 이 언어로 작성된 프로그램을 이용합니다. Lua가 흔히 웹 개발에 활용되는 JavaScript보다 더 가볍기에 신속하게 페이지를 띄워야 하는 위키에 적합한 셈이죠.

특징

  • 대소문자 구별하며, 예약어는 모두 소문자로 시작합니다. 웬만하면 소문자로만 프로그램을 짜는 것을 권장합니다.
  • null에 해당되는 예약어는 nil입니다. 그리고 false와 nil 이외에 0 같은 숫자를 boolean 기준으로 참으로 처리합니다.
  • 자료 타입은 nil, boolean, number, string, function, table, userdata, thread가 있습니다.
    • boolean - 참/거짓을 가리키는 자료형입니다. true, false 값이 있습니다.
    • number - 숫자 타입입니다. Lua는 정수형과 실수형을 구별하지 않았기 때문에 모든 수치형을 내부적으로 부동소숫점 숫자로 처리했습니다. 다만 5.3버전부터는 정수형을 지원하기 시작했습니다.
    • string - 문자열 타입입니다. 작은따옴표로 묶거나 아님 여러 줄 문자열은 대괄호 2개를 써서 (문자열)로 표현가능합니다.
    • function - 함수 타입입니다. 특이하게도 Lua는 함수형 자체를 변수로 쓸 수 있습니다.
    • table - 테이블 타입입니다. 파이썬의 Dictionary나 PHP의 연관배열(Associative Array), 또는 자바스크립트의 오브젝트(Object)와 유사한 개념입니다. 중괄호를 사용하며, 키=값 형식으로 사용합니다. 예를 들면 {1='리브라', 2='리디버그'} 이런 식으로 테이블을 정의 가능합니다. 특징 하나는 키 값을 따로 지정하지 않으면 키값이 정수 1부터 차례대로 배열됩니다. 즉 거의 대다수의 C-family 언어와는 달리 인덱스가 1부터 시작합니다.
    • userdata - 사용자 정의 자료형입니다.

사용 방법

  1. 온라인 인터프리터를 사용해봅시다. Lua 공식 홈페이지 데모.
  2. 다운로드 링크에서 다운로드 받은 뒤 C 프로그램에 헤더 형식으로 호출해서 사용할 수 있습니다.
  3. LuaDist 프로그램을 다운로드한 뒤 bin/lua.exe를 실행시키면 됩니다. 다만 버전이 5.1 기반이라 최신 버전인 5.4에서 지원하는 정수형 등을 지원하지 않는 단점이 있습니다.

기초 문법

모든 프로그래밍 언어가 그렇듯 기초를 배우는 것이 중요합니다. 여기서는 Lua 공식 홈페이지 데모를 활용하겠습니다. 또한 여기서는 LuaDist나 Scribunto 확장기능을 사용하는 사람들을 배려해서 5.3 이상에서만 호환되는 정수형 문법 등은 사용하지 않으려고 합니다.

Hello World 출력

-- Hello World 출력
print('Hello World!')

주석

Lua는 한 줄짜리 주석은 문장 앞에 -- 표시를 한 뒤 한 칸 띄워서 표시합니다. 또한 여러 줄 주석은 -- [[...]]를 사용하면 됩니다.

키워드

다음과 같은 단어는 Lua에서 에약된 단어로 변수명으로 지정할 수 없습니다. Lua는 예약된 키워드 숫자가 다른 언어들보다는 적은 편입니다. 참고로 Lua는 대소문자를 구별하는 프로그래밍 언어이므로 앞에 대문자로 치면 키워드로 인식되지 않습니다.

  • and
  • break
  • do
  • else
  • elseif
  • end
  • false
  • for
  • function
  • goto
  • if
  • in
  • local
  • nil
  • not
  • or
  • repeat
  • return
  • then
  • true
  • until
  • while

자료형

Lua의 자료형은 Javascript의 null 같이 아무것도 없다는 뜻을 가진 nil, 참/거짓을 나타내는 boolean(true, false 키워드를 사용합니다.), 숫자형 타입(number), 문자열(string), 테이블(table), 함수(function), 스레드(thread), 그리고 C언어를 활용해서 정의한 사용자 정의 자료형이 있습니다. 사용자 정의 자료형이나 스레드는 이해하는데 조금 난이도가 있는 만큼 여기서는 설명하지 않겠습니다.

우선 Lua는 nil이라는 키워드를 이용해 "아무것도 없음"을 정의합니다. 자바스크립트의 null, PHP의 NULL이나 파이썬의 None, C언어나 Java의 void와 유사한 역할을 하는 거죠. x=nil이라고 표시하면 변수 x는 아무것도 없는 상태라는 것을 의미하죠. print(x)를 하면 nil이 출력되며, nil은 연산에서도 사용할 수 없습니다. Lua는 파이썬에서 변수를 지워주는 키워드인 del 같은 키워드가 없기에 특정 변수를 지울 때는 nil값을 배정하는 식으로 변수를 지웁니다.

또 Lua에는 참/거짓을 의미하는 키워드인 true, false가 있습니다. 참과 거짓의 형태로 나오는 것을 boolean(불리언)이라고 부르는데요. 예를 들면 비교연산자를 이용한 연산 a==3는 a가 3이면 참, 3이 아니면 거짓이 되는 식이지요. Lua는 C언어와는 달리 둘 다 맞음을 의미하는 and 연산자는 &&으로 표현하지 않고 그냥 알파벳으로 and, or 연산자는 or, not 연산자는 not으로 표현합니다. 바로 이런 식으로요.

if x>3 and x<10 then
    print(x)
end

Lua는 대부분의 프로그래밍 언어와는 다르게 5.2버전 이전에는 정수형과 부동소숫점 형태를 구별하지 않았습니다. 내부적으로는 부동소숫점 형태로 처리했다가... 5.3버전부터는 내부 알고리즘에 의해 정수형/부동소숫점형을 처리하는 방식으로 바뀌긴 했습니다. 이런 특성 때문에 Lua는 정수형과 부동수숫점형을 엄격하게 구별하는 프로그래밍은 지양하는 것이 좋습니다.

Lua의 문자열 타입은 대부분의 프로그래밍 언어와는 대동소이하므로 자세한 설명은 하지 않겠습니다. Lua는 작은따옴표와 큰따옴표 모두 문자열을 표시할 때 사용가능합니다. 대괄호로도 문자열을 표시할 수 있는데 이때 코드에서 엔터를 치면 문자열에도 개행 문자가 반영이된다.

테이블

마지막으로 Lua에는 테이블이라는 형태가 있는데, 이는 C언어의 배열(array)이나 파이썬의 리스트(list)와 마찬가지로 여러 개의 변수를 하나로 묶어서 처리하는 타입입니다. 특이하게도 Lua는 파이썬같이 많은 언어에서 리스트와 딕셔너리(dictinary, 키값이 별도로 정의된 배열)/객체(Object, 자바스크립트에서 사용하는 용어)를 별도의 자료형으로 분류하는 것과는 다르게 테이블이라는 자료형 하나로 정의한다는 겁니다. 테이블은 중괄호로 묶인 형태({1,2,3})로 정의됩니다. 또한 숫자 뿐 아니라 NaN과 nil을 제외한 모든 숫자/문자열, 심지어는 테이블도 다른 테이블의 키값으로도 정의할 수 있습니다. 키값을 따로 지정할 때에는 키값에 해당하는 부분에 대괄호를 묶고, 뒤에 값을 지정하면 됩니다.

또 주의할 점이 하나 더 있는데, Lua의 테이블은 인덱스를 따로 지정하지 않을 경우 많은 프로그래밍 언어가 첫 인덱스를 0부터 시작하는 것과는 달리 1부터 시작한다는 점도 특징입니다.

아래의 테이블은 모두 같은 테이블을 의미합니다. Lua가 테이블을 정의하는 방법이 상당히 다양하다는 것을 알 수 있습니다.

tb = {1,3,5,7}
tb = {[1]=1, [2]=3, [3]=5, [4]=7}
tb = {}
tb[1]=1 tb[2]=3 tb[3]=5 tb[4]=7 -- lua는 세미콜론 없이도 한줄을 표현할 수 있는 언어입니다.
tb = {1,3,5,7} -- 여기서 5를 출력하려면
tb[3] -- 이렇게 작성합니다.
tb['3'] -- 불가능!

아래처럼 테이블은 딕셔너리와 배열을 섞은 형태도 가능합니다.

tb = {['1']=1, ['2']=3, ['첫 번째']=3}
tb = {['1']=1, ['2']=3, {2, 3}, {2, 1}, 'asdf'}
-- 이런 형태도 가능합니다.
print(tb['1']) -- 1 키값이 있으므로 딕셔너리 요소
print(tb[1]) -- table: 0x564267230cb0 ({2, 3})
print(tb[1][1]) -- 2
print(tb[3]) -- asdf 키값이 없으므로 배열 요소처럼 됩니다.

테이블은 또한 루아 모듈을 만드는데에 사용됩니다.

블록

Lua는 블록을 정의할 때 do 키워드를 사용해서 블록의 시작을 정의하고, end 키워드를 사용해서 블록의 끝을 표현합니다. if문에 의한 블록은 then으로 시작해서 end로 끝납니다. Lua는 C언어와는 달리 블록을 정의할 때 중괄호를 전혀 사용하지 않는 언어이고, 파이썬처럼 띄어쓰기 문법에도 엄격하지 않은 언어라는 점도 특징입니다.

변수 지정

많은 프로그래밍 언어들처럼 Lua도 배정 연산자로 등호(=)를 사용합니다. Lua는 자료형이 진위형(boolean), 숫자, 문자열, 테이블, 함수 등이 있으며, 함수 자체도 변수로 사용할 수 있다는 점이 있죠. 다음과 같은 코드도 사용이 가능합니다. 즉 함수 자체를 입력값으로 쓸 수도 있다는 거죠.

function add(a,b) 
    return a+b
end
function multiply(a,b) 
    return a*b
end
function operating(oper, a, b)
   if oper == add or oper == multiply then
        return oper(a,b)
    end
end
print(operating(add,5,3)) -- 함수 자체를 변수로 받을 수 있다. 8 출력
print(operating(multiply,5,4)) -- 20 출력

분기문과 반복문

분기문

대부분의 프로그래밍 언어처럼 Lua도 if문을 이용해서 분기문을 사용합니다. Lua는 BASIC이랑 유사하게 if (조건) then (수행문) end 형식을 사용합니다. 예를 들면 둘 중 더 큰 숫자를 출력하는 프로그램을 짜면 다음과 같습니다. 결과는 당연히 20이 출력됩니다.

a = 20
b = 10
if a >b then 
    print(a)
else
    print(b)
end

if 문이 여러개 있다면 elseif를 사용합니다.

a = 20
b = 10
if a >b then 
    print(a)
elseif a == b then
    print('a==b')
else
    print(b)
end

반복문

역시 대부분의 프로그래밍 언어처럼 Lua도 while과 for문이 있습니다. 우선 while문은 while (조건) do (실행) end로 실행 가능합니다. 1부터 10까지 숫자를 더한 값을 구하는 코드 예제입니다.

a = 0
b = 1
while b<=10 do
  a = a+b
  b = b+1
end

print(a)

마찬가지로 for문으로도 사용이 가능합니다. 단 형식은 for i=(시작),(끝),(증가수) do (실행문) end 형식이나 아니면 in 키워드를 사용해서 파이썬과 유사하게 for i in (테이블) do (실행문) end 형식으로도 사용 가능합니다.

a = 0
for b=1, 10 do
  a = a+b
end

print(a)

위키 모듈을 만들어보자

위키 모듈의 장점은 바로 분기문으로 처리해야 하는 내용을 처리할 수 있기 때문입니다.

BanansArgs 예제

모듈:BananasArgs를 이용해서 위키에서 Lua 모듈이 어떻게 동작하는지 파악해봅시다.

1. 우선 미디어위키 루아 모듈은 local 키워드를 이용해서 내부적으로 사용할 빈 테이블을 정의합니다. 이 테이블에서 루아 모듈을 정의할 겁니다.

local p ={}

2. 각 모듈에서 출력하고 싶은 내용은 테이블 p 안의 함수로 정의합니다. 예를 들면 입력 값 하나도 없이 출력하는 함수를 정의하고 싶으면 다음과 같이 입력하시면 됩니다.

-- 출력시에는 이런 식으로 씀: {{#invoke:BananasArgs|hello_world}}
function p.hello_world()
    return "Hello, world!"
end

3. 매개변수가 있는 경우에는 다음과 같이 함수를 정의하시면 됩니다.

-- 한개의 매개변수
-- 이런 식으로 씀: {{#invoke:BananasArgs|hello|민준}}
function p.hello(frame)
    local name = frame.args[1]
    return "안녕하세요, " .. name .. "님!"
end

4. 매개변수가 2개 이상 있을 때에는 다음과 같이 함수를 정의하시면 됩니다. 중요한 것은 함수에서 입력값을 여러 개 입력하는 방식이 아닌 frame이라는 테이블 하나를 입력값으로 받는다는 점입니다.

-- 두개의 매개변수
-- 이런 식으로 씀: {{#invoke:BananasArgs|add|5|3}}
function p.add(frame) -- 입력 변수를 테이블 하나로 처리.
    local num1 = tonumber(frame.args[1]) 
    local num2 = tonumber(frame.args[2])
    return num1 + num2
end

5. 매개변수에 이름을 부여하고 싶을 때는 다음과 같이 테이블에 키값을 지정하면 됩니다. 참고로 매개변수에 이름을 부여하는 방식과 숫자만 사용하는 방식을 섞어서 사용할 수 있습니다.

-- 이름을 가진 매개변수
-- 이런 식으로 씀: {{#invoke:BananasArgs|count_fruit|바나나=5|사과=3}}
function p.count_fruit(frame)
    local num_bananas = frame.args['바나나']
    local num_apples = frame.args['사과']
    return '저는 바나나 ' .. num_bananas .. '개와 사과 ' .. num_apples .. '개를 가지고 있습니다.'
end

6. Lua 모듈의 매우 좋은 점은 for문과 frame.args 조합을 통해 매개변수 자체도 호출이 가능하다는 겁니다. 다시 말해 매개변수명을 제한된 형태가 아닌 임의의 형태로도 호출할 수 있다는 것이지요.

-- 매개변수를 반복해서 읽기
-- 이런 식으로 씀: {{#invoke:BananasArgs|custom_fruit|파인애플=10|키위=5}}
function p.custom_fruit(frame)
    local result = '저는'
    for name, value in pairs(frame.args) do
        result = result .. ' ' .. name .. ' ' .. value .. '개'
    end
	result = result .. '를 가지고 있습니다.'
    return result
end

7. 마지막으로 중요한 것! 바로 return p라는 명령어를 입력해서 모듈은 값을 반환해주어야 합니다. 그래야 Lua 모듈을 사용할 수 있습니다.

모듈 사용할 때는 호출, 또는 invoke 태그를 사용합니다. {{#호출:BananasArgs|(함수명)|(변수명)}} 같은 형식을 사용합니다. 예를 들면 아래와 같이 입력해봅시다.

{{#호출:BananasArgs|hello|{{사용자}}}}

그럼 결과는 다음과 같이 출력됩니다 : 안녕하세요, 사용자님!

참조