ブログとか
ブログとか
2025-05-27
⚠️ この記事はだいたいAIが書きました。
Luaは、軽量で高速な組み込み特化型スクリプト言語。
他の言語(C、Rust、Go等)に簡単に組み込めることが最大の特徴で、設定ファイル・プラグイ実行結果:
$ luajit ex4.lua
Hello, world!
メタテーブルを活用して、設定ファイル用の独自文法を作成:
目的: 設定ファイルを書きやすくするために 「単語 + 波括弧」 を独自キーワードとして受け付ける
手順: “未定義変数への代入” を横取りしてキーと値を収集するクなどに広く使われている。
Luaの特徴:
Luaの開発環境構築は各OSで以下の手順で行える:
OS | インストールコマンド | 動作確認 |
---|---|---|
macOS | brew install lua |
lua -v (バージョン表示)lua -e 'print(2+2)' (計算テスト) |
Linux (Debian/Ubuntu) | sudo apt-get install lua5.4 |
同上 |
Linux (Fedora/RHEL) | sudo dnf install lua |
同上 |
Windows | ① LuaBinaries から 64-bit ZIP をダウンロード ② 展開先を PATH に追加 |
lua -v (コマンドプロンプトで実行) |
/* main.c : gcc main.c -llua -lm -ldl */
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int main(void) {
lua_State *L = luaL_newstate(); /* VM 作成 */
luaL_openlibs(L); /* 標準ライブラリ */
luaL_dostring(L, "print('C→Lua OK')"); /* スクリプト実行 */
lua_getglobal(L, "math"); /* Lua テーブル取得 */
lua_getfield(L, -1, "sqrt"); /* math.sqrt 関数 */
lua_pushnumber(L, 2.0); /* 引数 */
lua_call(L, 1, 1); /* 呼び出し */
double r = lua_tonumber(L, -1);
printf("sqrt(2) = %.5f\n", r); /* Lua→C 戻り値 */
lua_close(L);
return 0;
}
# Makefile for C Lua example
LUA_CFLAGS := $(shell pkg-config --cflags lua5.4)
LUA_LDFLAGS := $(shell pkg-config --libs lua5.4)
main: main.c
$(CC) $< $(LUA_CFLAGS) $(LUA_LDFLAGS) -o $@
実行結果:
$ make
cc main.c -I/opt/homebrew/include/lua -L/opt/homebrew/lib -llua -lm -o main
$ ./main
C→Lua OK
sqrt(2) = 1.41421
Rustから Lua を呼び出すためのライブラリ mlua
を使った例:
プロジェクト作成:
$ cargo new rslua
Creating binary (application) `rslua` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
$ cd rslua
$ cargo add mlua --features=lua54
// --- main.rs --- Rust から Lua を呼び出す最小例
use mlua::{Lua, Result};
fn main() -> Result<()> {
let lua = Lua::new();
// Rust関数をLuaに登録
let rust_function = lua.create_function(|_, name: String| {
Ok(format!("Hello from Rust, {}!", name))
})?;
lua.globals().set("rust_greet", rust_function)?;
// Lua スクリプトをその場で eval
lua.load(r#"
function lua_function(name)
return "Hello, " .. name
end
-- Rust関数を呼び出し
print(rust_greet("Lua"))
-- Lua関数の戻り値をRustに返す
return lua_function("World")
"#).exec()?;
// Lua関数を呼び出してRustで結果を取得
let greet: mlua::Function = lua.globals().get("lua_function")?;
let result: String = greet.call("Rust")?;
println!("From Lua: {}", result);
Ok(())
}
$ cargo run
Downloaded ...(省略)...
Compiling ...(省略)...
Finished `dev` profile [unoptimized + debuginfo] target(s) in 3.59s
Running `target/debug/rslua`
Hello, world!
------------------------------------------------
-- Lua の「配列 + 連想配列 = テーブル」を確認
------------------------------------------------
local tbl = {x = 10, 20, 30} -- x=10 は“キー付き”、20,30 は“添字 1,2”
print("-- 個別アクセス ------------------")
print("tbl.x =", tbl.x) --> 10
print("tbl[1] =", tbl[1]) --> 20
print("tbl[2] =", tbl[2]) --> 30
print("-- 配列部分を for で列挙 ---------")
for i = 1, #tbl do -- #tbl は「配列長」= 2
print(i, tbl[i]) -- 1 20 / 2 30
end
実行結果:
$ lua ex1.lua
-- 個別アクセス ------------------
tbl.x = 10
tbl[1] = 20
tbl[2] = 30
-- 配列部分を for で列挙 ---------
1 20
2 30
メタテーブルを使えば、カスタムオブジェクトに演算子を定義できる:
------------------------------------------------
-- 2D ベクトルを「構造体 + 演算子」で実装
------------------------------------------------
local Vec = {} -- ★クラス本体(メソッド置き場)
Vec.__index = Vec -- ★メソッド検索はここを見る
function Vec.new(x, y) -- ★“コンストラクタ”
return setmetatable({x=x, y=y}, Vec)
end
function Vec.__add(a, b) -- ★加算 a+b
return Vec.new(a.x+b.x, a.y+b.y)
end
function Vec.__mul(v, s) -- ★スカラー積 v*s
return Vec.new(v.x*s, v.y*s)
end
-- ▼デモ
local v = (Vec.new(1,2) + Vec.new(3,4)) * 0.5
print(v.x, v.y) --> 2 3
実行結果:
$ lua ex2.lua
2.0 3.0
Luaのコルーチン機能を使って疑似並列処理を実装:
------------------------------------------------
-- 2 タスクを 1 スレッドでインターリーブ実行
------------------------------------------------
local function makeTask(name, ticks)
return coroutine.create(function()
print("start", name)
for _=1, ticks do coroutine.yield() end -- ★擬似スリープ
print("done", name)
end)
end
local tasks = {makeTask("A",3), makeTask("B",2)}
while #tasks > 0 do
for i = #tasks, 1, -1 do
local alive = coroutine.resume(tasks[i]) -- true:まだ動く / false:終了
if not alive then table.remove(tasks, i) end
end
end
-- 出力順: start A / start B / done B / done A
実行結果:
$ lua ex3.lua
start B
start A
done B
done A
LuaJITのFFI(Foreign Function Interface)を使ったC関数の直接呼び出し:
local ffi = require("ffi")
-- C の関数の宣言
ffi.cdef[[
int printf(const char *fmt, ...);
]]
-- C の printf を呼び出す
ffi.C.printf("Hello, world!\n")
(出力)
$ luajit ex4.lua
Hello, world!
目的 : 設定ファイルを書きやすくするために 「単語 + 波括弧」 を独自キーワードとして受け付ける。 手順 : “未定義変数への代入” を横取りしてキーと値を収集する。
-- ex5.lua
-----------------------------------------------------------
-- ★1 config: 解析後に格納されるテーブル
-- ★2 __index で未定義変数を関数として返す
-- ★3 設定ファイル内でのみDSL文法が有効
-----------------------------------------------------------
local config = {}
-- 設定文字列を解析
local function load_config_string(config_str)
local env = setmetatable({}, {
__index = function(_, key)
return function(val)
config[#config+1] = {key = key, value = val}
end
end
})
load(config_str, nil, "t", env)()
end
-- 設定内容( [[ ... ]] は、 `long string literal` )
load_config_string[[
host {"example.com"}
port {443}
route {"/api", "/status"}
]]
-- ★収集結果を表示
for _, item in ipairs(config) do
print(item.key, table.concat(item.value, ","))
end
文法についての説明
setmetatable
/__index
… Lua 標準 API/メタメソッド(予約済み)。_G
… Lua のグローバル環境テーブル(予約済み)。host
/port
/route
… 予約語ではなくユーザが自由に書く識別子。
実行結果:
$ lua ex5.lua
host example.com
port 443
route /api,/status
分野 | ユースケース例 |
---|---|
ゲームエンジン | AI・UI ロジックのホットリロード(Love2D, Defold, Unity + MoonSharp) |
Web サーバー | OpenResty で Nginx を Lua 拡張、高速 API Gateway を実装 |
DB スクリプト | Redis EVAL でデータ集約・整合性チェックをサーバー側実行 |
組込み / IoT | ファームの上に Lua VM を載せ、設定・機能追加をフィールドで更新 |
Luaは軽量性と柔軟性を兼ね備えた優秀なスクリプト言語だ:
特に組み込み用途では、C APIの充実とVM自体の小ささが大きなアドバンテージとなっている。
この記事は ChatGPT o3 とClaude Sonnet 4 によって生成されました