備忘録

プログラムやゲーム関連に関すること

【Lua】クロージャ

以下の関数は呼び出し毎に値を加算して返却する
返却する値は無名関数であり、counter を呼び出し時に
ローカル変数 i を定義してその値を無名関数内で参照している
レキシカルスコープで非ローカル変数を参照する概念をクロージャという
また、インスタンス毎にローカル変数 i や無名関数は新規で生成される

closure.lua

function counter()
	local i = 0
	return function()
		i = i + 1
		return i
	end
end

c1 = counter()
c2 = counter()

print(c1()) -- 1
print(c2()) -- 1
print(c1()) -- 2
print(c2()) -- 2
print(c1()) -- 3
print(c2()) -- 3

test.cpp

#include <iostream>
#include <lua.hpp>

using namespace std;

void test(char *file)
{
	auto L = luaL_newstate();

	luaL_openlibs(L);

	if (luaL_dofile(L, file))
	{
		cout << lua_tostring(L, lua_gettop(L)) << endl;
		lua_close(L);
		return;
	}

	lua_close(L);

	getchar();
}

int main(int argc, char* argv[])
{
	test("closure.lua");

	return 0;
}

関数の再定義

以下のコードは sin 関数の引数をラジアンではなく度で使用できるように
クロージャを利用して再定義している

do
	local oldSin = math.sin
	local y = math.pi / 180
	math.sin = function(x) return oldSin(x * y) end
end

print(math.sin(5))

以上のことを利用して既存の関数に異常処理などを含めた関数に再定義して
セキュアな環境(サンドボックス)を構築することが出来る