🈷️

忙しい人向けのLua

に公開

TL;DR

しっかり学びたい方は書籍や他の方の記事でLuaについて学ぶことを推奨します。
(流石にインターネットのどこかにあるでしょう。)
しかしながら、期限まで時間の余裕がないという方もおられるかと思います。
そういう場合の応急処置を目的として、Luaに必要な知識をできるだけ最小限にまとめます。
そのため、理解を妨げないように説明を意図的に簡略化している箇所があります。
Luaのバージョンは5.4です。

インストール手順とHello,World

インストール手順(Linux)

sudo apt install lua5.4

Hello,World

print("Hello,World")

変数

変数の定義方法

変数の定義は変数名=値またはlocal 変数名=値で行う。
localがない場合はグローバル変数扱いとなる。
値を代入しない場合、初期値はnil(後述)となる。

変数の型

Luaは動的型付け言語に属する。
型を調べたいときはtype関数を使用する。

nil

値がないことを示す。JavaScriptのnullとかPythonのNoneに近い。

論理値型(boolean)

truefalseがある。
演算はand,or,notが可能。

数値(number)

整数または実数を表す。大きさは64ビットであるため、
整数値を扱う場合はオーバーフローに注意する必要がある。
基本的には整数と実数の使い分けを意識する必要はない。
以下の演算が可能

3 + 5
3 - 5
3 * 5
3 / 5
3 // 5
3 % 5
3 ^ 5

上から順番に加減乗除、除算(商が整数値)、剰余、べき乗

文字列(string)

変更不能なバイト列を表す。エンコードを考慮しないのでプログラマが意識する必要がある。
シングルクォーテーションまたはダブルクォーテーションのどちらかで囲む。
文字列の連結は..演算子を使用する。

local str1 = "Hello,"
local str2 = 'World'
print(str1..str2)

関数(function)

Luaで定義した関数かC言語で作成した関数を表す。

ユーザ定義型(userdata)

任意のC言語データを表す。ユーザ定義型はLua内では作成できない。
Luaによってメモリ管理されるfull userdataと、
C言語のポインタ値を表すlight userdataの2種類がある。

スレッド(thread)

コルーチンを実装するために使われる。
OSスレッドとは関係がないため、スレッドをサポートしない環境でもコルーチンは使える。

テーブル

連想配列を表す。
連想配列は、keyとvalueの組で構成され、JavaScriptでいうハッシュやPythonでいう辞書に近い。
数字をkeyとすることで通常の配列としても使えるが、インデックスは1から始まることに注意する。
valueがnilになるkeyはテーブルの要素とはみなされない。
また、テーブルの要素ではないkeyのvalueはnilとみなされる。
#テーブル名でテーブルの要素数を取得できる。

制御フロー

条件分岐

if~elseif~else

if 条件式1 then
    処理1
elseif 条件式2 then
    処理2
else
    処理3
end

以下は条件式でよく使われる演算子である。

local x = 5
if x == 5 then
if x ~= 5 then
if x < 5 then
if x <= 5 then
if x > 5 then
if x >= 5 then

ループ

ループからの脱出にはbreakのみ使用可能で**continueはない。**

while

local n = 10
while n > 0 do
    print(n)
    n = n - 1
end

repeat

local n = 10
repeat
    print(n)
    n = n - 1
until n < 0

for

数字のループ

for i = 0, 10, 2 do
    print(i)
end

これは、0,2,4,6,8,10を1行ずつ表示する。

テーブルのループ

ただの配列の場合はipairs関数を使うとインデックスも取得できる。

local array = {4, 5, 6}
for index, value in ipairs(array) do
print(index, value)
end

連想配列の場合はpairs関数を使うとkeyとvalueを取得できる。

local table = {first = 1, second = 2, third = 3}
for key, value in pairs(table) do
print(key, value)
end

関数

関数の定義方法

functionキーワードで始まり、関数名の後に引数を書く。
関数にlocalをつけることもできる。
可変長の引数を使用したい場合は...と書く。
最後にendキーワードで終わる。

local function add_one(x)
    x = x + 1
    return x
end

関数はオブジェクトとして扱うことができるため、下記の書き方も可能。

local f = function(x)
    x = x + 1
    return x
end

メタテーブル

値に関連づけられた、演算子の挙動を定義しているテーブル。
getmetable関数を呼び出すことで取得することができる。
また、setmetatable関数を呼び出してメタテーブルを変更することで、演算子の挙動を変更することができる。
例えば、key__addに対する関数を変更すると+演算子の挙動が変化する。

コルーチン

公式リファレンスでは「協調的なマルチスレッディング」とのこと。

coroutine.create関数の引数にコルーチン内で実行する関数を渡して呼び出すと、
コルーチンに対するハンドル(他のコルーチンと区別する識別子)を返す。
このハンドルはthread型であり、他のcoroutine操作用の関数に引数として渡す。

コルーチンを開始するためにはcoroutine.resume関数を呼び出す。
このとき、第一引数にはハンドルを渡す。残りの引数はコルーチン内で実行する関数に渡される。
coroutine.resumeはコルーチン内の処理が一区切りした段階で戻り値を得る。
もう一度coroutine.resume関数を呼び出すと、前回の続きから処理を再開する。

コルーチン内の処理が一区切りするための条件は、次のいずれかになる。

  • コルーチン内で実行する関数が最後の処理を実行して終了する。
  • コルーチン内で実行する関数がcoroutine.yield関数を呼び出す。

最後の処理を実行して終了したコルーチンに対するcoroutine.resume関数の呼び出しはエラーとなる。

オブジェクト指向的な使い方について

classキーワードのようなものはないので、テーブルとメタテーブルを使う。
コンストラクタはJavaScript寄りで、メタテーブルはPython寄りな感じ。

Person = {}
Person.hello = function(self, target)
        print("Hello,".. target .. ". My name is ".. self.name)
end

Person.new = function(name, age)
    local this = {}
    this.name = name
    this.age = age

    setmetatable(this, {__index = Person})

    return this
end

local taro = Person.new("Taro", 24)
taro:hello("Hanako")

最後に

C言語に組み込むのが主な使用用途になっているためか、リファレンスマニュアルのほとんどがC言語とのインタフェースに関する説明で埋まっています。Luaのスクリプトの書き方だけではなく、そちらについても知る必要があるのであればしっかり学んだほうがいいかと思います。

Discussion