루아 프로그래밍 기초: 데이터 구조와 입출력

서론 (루아 5.3 기반 프로그래밍)

루아는 다른 언어와 몇 가지 공통점이 있지만, 다음과 같은 독특한 특성을 가지고 있습니다:

  1. 확장성
  2. 간결성
  3. 효율성
  4. 이식성

루아 사용자는 크게 세 가지 그룹으로 나뉩니다:

  1. 애플리케이션에 내장하여 사용
  2. 독립적으로 사용
  3. C와 함께 사용

공식 웹사이트: http://www.lua.org

사용자 커뮤니티: http://lua-users.org

1장: 루아 언어 시작하기

청크(Chunk)는 명령어나 표현식의 시퀀스로 구성됩니다.

prog.lua 파일 첫 줄에 #!/usr/bin/lua를 추가하면 직접 실행할 수 있습니다: $ ./prog

-i 매개변수를 사용하면 루아 인터프리터가 지정된 프로그램 청크를 실행한 후 대화형 모드로 진입합니다: lua -i prog.lua

대화형 모드에서 dofile("prog.lua")를 실행하면 해당 파일이 즉시 실행됩니다.

-e 매개변수를 사용하면 명령줄에서 직접 코드를 입력할 수 있습니다: $ lua -e "print(\\"hello\\")"

3장: 숫자

루아 5.3부터는 64비트 정수와 배정밀도(최대값 2^53) 부동소수점을 지원합니다. 최적화된 루아 모드로 컴파일하면 32비트 정수와 단일 정밀도 부동소수점을 지원합니다. 루아 5.2 이전 버전에서는 모든 숫자가 배정밀도 부동소수점 형식으로 표현되었습니다.

type(3)과 type(3.0) 모두 "number"를 반환하며, -3 == -3.0의 결과는 true입니다.

math.type(3)은 integer를 반환하고, math.type(3.0)은 float를 반환합니다. 이를 통해 정수와 부동소수점을 구분할 수 있습니다.

두 피연산자 모두 정수 값이면 결과도 정수 값이고, 그렇지 않으면 결과는 부동소수점 값입니다.

하지만 나눗셈 연산의 결과는 항상 부동소수점입니다. 루아 5.3은 정수 나눗셈을 위해 바닥 나눗셈(floor division)이라는 새로운 산술 연산자 "//"를 도입하여 결과가 정수임을 보장합니다. 거듭제곱(^) 연산의 결과는 항상 부동소수점입니다.

math 라이브러리에는 삼각함수, 지수함수, 반올림함수, max, min, floor, ceil, random, pi, huge(대부분의 플랫폼에서 inf를 나타냄) 등이 포함됩니다.

4장: 문자열

문자열은 텍스트를 표현하는 데 사용되며, 루아에서 문자열은 변경 불가능한 값(immutable value)입니다.

작은따옴표로 문자열을 선언하면 큰따옴표는 이스케이프할 필요가 없습니다. 큰따옴표로 문자열을 선언하면 작은따옴표는 이스케이프할 필요가 없습니다.

여러 줄 문자열은 \[==\[와 \]==\]로 선언할 수 있으며, 등호의 개수는 0 이상이어야 합니다. 주석도 비슷하게 사용합니다: -- \[==\[와 \]==\] .

이스케이프 시퀀스 \\ z는 문자열 뒤의 모든 공백 문자를 건너뛰고 첫 번째 공백이 아닌 문자가 나올 때까지 진행합니다.

5장: 테이블

테이블은 루아에서 가장 중요하고(사실상 유일한) 강력한 데이터 구조입니다.

테이블 인덱스로 사용될 때 정수로 변환 가능한 모든 부동소수점은 정수로 변환됩니다. 예를 들어, a\[2.0\]=10 표현식을 실행할 때 키 2.0은 2로 변환됩니다.

일반 생성자:

-- 대괄호로 감싼 표현식을 사용하여 각 인덱스를 명시적으로 지정합니다.
-- 이를 통해 음수 인덱스를 사용할 수 있고, 일반 생성자에서 사용할 수 없는 식별자를 인덱스로 사용할 수 있습니다.
연산자이름 = {["+"] = "더하기", ["-"] = "빼기", ["*"] = "곱하기", ["/"] = "나누기"}
숫자 = 20; 기호 = "-"
배열 = {[숫자 + 0] = 기호, [숫자 + 1] = 기호..기호, [숫자 + 2] = 기호..기호..기호}
print(연산자이름[기호])   -- > 빼기
print(배열[22])        -- > --- 

시퀀스(sequence)는 지정된 n개의 양수 키로 구성된 집합{1, ..., n}으로 형성된 테이블입니다(nil 값의 키는 실제로 테이블에 존재하지 않습니다).

루아 언어는 시퀀스 길이를 얻는 연산자 #를 제공하지만, nil 값이 있는 목록에 대해서는 시퀀스 길이 연산자 #가 신뢰할 수 없습니다.

-- pairs 반복기를 사용하여 테이블의 키-값 쌍을 순회할 수 있습니다.
-- 순회 중 요소의 출현 순서는 임의적일 수 있으며, 동일한 프로그램을 실행할 때마다 다른 순서가 생성될 수 있습니다.
-- 목록의 경우 ipairs를 사용할 수 있습니다. 이 경우 루아는 순서대로 순회가 이루어지도록 보장합니다.
테이블 = {10, print, x = 12, k = "안녕"}
for 키, 값 in pairs(테이블) do
    print(키, 값)
end

안전한 접근:

local 데이터 = {x = {y = {z = 10}}}
local 결과 = (((데이터 or {}).x or {}).y).z
print(결과) --10
결과 = (((데이터 or {}).x or {}).y).x
print(결과) --nil

6장: 함수

호출 f(g())에서 f의 매개변수가 고정된 경우, 루아 언어는 g의 반환값 개수를 f의 매개변수 개수와 일치하도록 조정합니다. 이는 우연이 아니며, 실제로 이는 다중 할당의 논리와 정확히 일치합니다.

함수 호출을 한 쌍의 괄호로 감싸면 단 하나의 결과만 반환하도록 강제할 수 있습니다: print((함수())) --> a

table.pack은 함수의 매개변수 목록을 테이블로 변환하고, table.unpack은 테이블을 일련의 반환값으로 변환하여 다른 함수의 매개변수로 사용할 수 있도록 합니다.

7장: 입출력

io.write(a..b..c)는 피해야 하며, io.write(a,b,c)를 사용해야 합니다. 후자는 더 적은 리소스로 동일한 효과를 내며, 더 많은 연결 작업을 방지할 수 있습니다.

-- io.open 함수를 사용하여 파일을 열고, read와 write 메서드를 사용하여 스트림에서 읽고 쓸 수 있습니다.
local 파일이름 = "테스트.lua"
local 파일 = io.open(파일이름, "r")
local 내용 = 파일:read("*a") -- 모든 내용 읽기
local 내용 = 파일:read("*l") -- 한 줄 읽기
local 내용 = 파일:read(5)    -- 5바이트 읽기
print(내용) 파일:close()

라이브러리는 세 개의 미리 정의된 C 스트림 핸들(io.stdin, io.stdout, io.stderr)을 제공합니다. 예를 들어,

다음 코드를 사용하여 표준 오류 스트림에 직접 정보를 쓸 수 있습니다:

local 메시지 = "오류 메시지: ...\n"
io.stderr:write(메시지)

io.input과 io.output 함수는 완전한 I/O 모델과 단순한 I/O 모델을 혼합하여 사용할 수 있습니다.

local 임시 = io.input() -- 현재 입력 스트림 저장
io.input("테스트.lua") -- 새로운 현재 입력 스트림 열기
-- 새로운 입력 스트림에 대한 작업 수행
print(io.input():read("*l"))
print(io.read("*l"))    -- 위와 동일한 작용
io.input():close()      -- 현재 스트림 닫기
io.input(임시)          -- 이전의 현재 입력 스트림 복원
io.input():close()      -- 현재 스트림 닫기

현재 위치 가져오기 및 설정:

function 파일크기 (파일)
    local 현재위치 = 파일:seek()    -- 현재 위치 저장
    local 크기 = 파일:seek("end")  -- 파일 크기 가져오기
    파일:seek("set", 현재위치)      -- 원래 위치 복원
    return 크기
end

local 파일이름 = "테스트.lua"
local 파일 = io.open(파일이름, "a")
파일:seek("end")                      -- 파일 끝으로 이동
파일:setvbuf("full")                  -- 전체 버퍼링 설정(다른 옵션: full/no/line)
파일:write("\n--추가 내용")
파일:flush()                          -- 스트림 f 플러시
--추가 내용

기타 시스템 호출:

print(os.getenv ("HOME")) -- > /home/lua
os.execute("ls")
-- os.execute 함수와 마찬가지로 popen은 시스템 명령을 실행하지만
-- 해당 함수는 명령의 입력/출력을 리디렉션할 수도 있습니다
local 파일 = io.popen ("ls .", "r")
for 항목 in 파일:lines() do
    print(항목)
end
os.exit(0)

8장: 부가 지식

지역 변수의 범위는 변수를 선언한 코드 블록의 마지막 유효(non-void) 문장에서 종료되며, 레이블은 무효한(void) 문장으로 간주됩니다.

 1 local 데이터 = {1, 2, 3, 4}
 2 local 인덱스 = 1
 3 while 데이터[인덱스] do
 4     if 데이터[인덱스] == 2 then
 5         인덱스 = 인덱스 + 1
 6         goto 계속 -- 변수 var의 범위 밖으로 점프
 7     end
 8     print(데이터[인덱스])
 9     인덱스 = 인덱스 + 1
10     local 변수 = 8
11     ::계속::
12     --print(변수) -- <goto 계속> at line 6 jumps into the scope of local '변수'
13     --print(인덱스)   -- <goto 계속> at line 6 jumps into the scope of local '변수'
14 end
15 
16 -- 코드 블록 내의 레이블은 외부에서 보이지 않음
17 --goto 계속    -- no visible label '계속' for <goto> at line 17

태그: 루아 프로그래밍 언어 데이터 구조 입출력 테이블

5월 28일 22:43에 게시됨