tbl[ "age" ] = 10
tbl[ "name" ] = "test"
-- キーは数値でも指定できる
tbl[ 1 ] = 10;
-- 削除をするには nil をセットする
tbl[ "name" ] = nil
-- iterate すると削減されたことがわかる
for key, val in pairs( tbl ) do
print ( key )
print ( val )
end
___
■ ソート(sort)
SYNTAX
table.sort( array [, function ] )
DESC
配列を昇順にソートする。
local a = {7, 5, 3};
table.sort(a);
-- 結果を表示
for i=1, #a do
print(a[i]);
end
比較用の関数を指定する。
a = {}
a[1] = { name="a", price=300 };
a[2] = { name="b", price=100 };
a[3] = { name="c", price=200 };
function cmpfunc( a, b )
return a.price < b.price
end
table.sort( a, cmpfunc );
for i=1, #a do
print( a[i].price );
end
___
■ foreach(イテレート)
for t, val in pairs( members ) do
for k, v in pairs(val) do
print( k, v );
end
end
while で利用する
k, v = next( player1 );
while (k) do
print( v );
k, v = next( player1, k );
end
___
■ 配列(Array)
___
■ 配列
POINT
配列はテーブルのキーを数値にすることで利用する。
テーブルの特殊系にすぎない。
. Table{ Arr{} }
-- Constructor 起動( この処理は必須 )
a = {};
-- list 表記
-- 初期化リストつき
local a = { "x", "y", "z" };
print( a[1] );
数値 index として扱う
a = {}
-- 追加する
a[ #a + 1 ] = "a"
a[ #a + 1 ] = "b"
-- イテレートする
for i = 1, #a do
local s = a[ i ]
print( s )
end
SYNTAX
string.gmatch( string, pattern )
DESC
split がないため gmatch で代用する。
gmatch はマッチしたすべての要素を順に返すイテレータ関数を返すため
for - in と併用して文字列を分割する。
local s = "d:/foo/bar/goo.txt";
local a = {}
for w in string.gmatch(s, "[^/]+") do
table.insert(a, w);
end
for i=1, #a, 1 do
print ( i .. " = " .. (a[i]) )
end
___
■ 部分文字列
string.sub( string, s, e )
local ret = string.sub( "aaa___bbb", 1, 3 );
-- 7番目より後ろ
local ret = string.sub( "aaa___bbb", 7 );
print( ret );
___
■ match(検索)
SYNTAX
string.match( string, pattern [, index ] )
DESC
pattern にマッチする文字列を string から返す。
index が指定された場合は index の位置から検索をする。
-- RET hello
local ret = string.match("hello world", "%w+")
-- RET f
string.match( "foobar", "[a-z]" );
___
■ find(インデックス検索)
SYNTAX
string.find( string, regexp [, index ] )
RET
start, end : マッチした文字列の開始, 終了位置インデックス
nil : マッチしない場合
DESC
regexp にマッチする文字列を string から検索して
開始、終了の index を返す。
index が指定された場合は index の位置から検索をする。
-- 1, 4
s, e = string.find( "test", "%a*");
-- 4, 6
local s, e = string.find ( "aaa___bbb", "___" )
-- 拡張子を返す
path = "d:/foo/test.txt"
local idx = string.find( path, '%.' )
local ext = string.sub( path, 0, idx - 1 )
-- 1, 3
local path = "c:/foo.txt"
local s, e = string.find( path, "[Cc]:/" );
function ( a, b, ... )
a = select(5, ...); -- 可変引数 5 番目取得.
end
string.format
function test(...)
local arr = {...};
for i=1, #arr do
print( arr[i] );
end
end
do
test( "a", "b", "c", 10 );
end
function fnMyUpper( s )
local l = string.len( s );
local str = string.upper( s );
return l, str;
end
do
local len, s;
len, s = fnMyUpper( "aiueo" );
print( len.."\t"..s);
end
a = {}
a[1] = { name="a", price=300 };
a[2] = { name="b", price=100 };
a[3] = { name="c", price=200 };
table.sort( a, function ( a, b ) return a.price > b.price end );
for i=1, #a do
print( a[i].price );
end
POINT
Lua は Table を利用して Object をあらわす。
構造体としてとらえることも可能
Method の実体は Table の Field の値として関数があるだけ。
Lua Table を利用することで, Object を作成できる。 { data , method ... }
キーをメンバ変数名とみなせば、構造体としても表現できる。
Method には InstanceData をわたしたい.
file.open( file ) ---> file:open(); となる.
-- MetaTable
Colormeta = {
-- + の演算はこの関数でオーバーライド
__add = function(a, b)
local r, g, b = (a.r+b.r), (a.g+b.g), (a.b+b.b)
return newrgb( r, g, b );
end,
-- 文字列表現
__tostring = function(a)
return string.format("rgb %3d %3d %3d", a.r, a.g, a.b )
end,
}
-- ctor
function Color( r, g, b )
local tbl = { r = r or 0, g = g or 0, b = b or 0 };
-- 毎度設定しないとだめ
setmetatable( tbl, Colormeta );
return tbl;
end
-- テーブルを作成して返す
g = Color(0, 255, 0);
b = Color(0, 0, 255);
-- MetaMethod を使う。
cyn = g + b;
print( cyn );
function T.new(value)
--
local obj = {
value = value,
toString = function(self)
return "T: value=" .. tostring(value)
end
}
return obj
end
-- new clsFoo(); の模倣.
obj = T.new(5)
print( obj:toString() )
obj2 = T.new(7)
print( obj2:toString() )
[ : ] を利用した関数定義
function object:read( a, b, c )
-- self は local 変数
print( self );
end
function object.read( self, a, b, c )
-- self は local 変数
print( self );
end
新規の型を定義できないため、クラスのインスタンスを作成するには
コンストラクタに相当する関数内でテーブルを作成して返す。
function Vector( x, y, z )
-- インスタンスに相当するテーブルを作成
local tbl = { x=x, y=y, z=z }
-- メソッドを定義
tbl.length = function( self )
return math.sqrt( self.x*self.x + self.y*self.y + self.z*self.z )
end
tbl.normalize = function( self )
local n = self:length()
self.x = self.x / n
self.y = self.y / n
self.z = self.z / n
end
return tbl
end
-- インスタンスを作成
local v = Vector( 1, 2, 3 )
-- メソッドをよびだす
v:normalize()
local len = v:length()
print ( len )
___
■ Closure
source code 上のまとまりのある単体.
Cの関数を作成するとき、いくつかの値を関連付けて Cのクロージャ を作ることができる。
( 関数に変数を付属させたもの関数のこと )
( 関数内で使用するdataを関数内にとじこめる )
Table とは異なり, data を隠ぺいすることができる。
a = {}
local x = 20
for i=1,10 do
local y = 0
a[i] = function () y=y+1; return x+y end
end
クロージャはすべて同じ x を参照するが、それぞれ異なった y を参照する。
(y の解決を実行時の環境ではなく、 定義時の環境で行っているため.
for i=1,10 do
print(a[i]())
end
-- 実行結果は 21 が 10 個表示される
-- file handle 経由
do
local file = io.open("d:/lua/test.txt", "r");
if ( file ) then
-- filehandle:read( format );
-- [ *l | *a | *n ]
local t = file:read("*a");
print(t);
else
print("no file");
end
end
-- file handle 経由
local fp = io.open("d:/lua/test.txt", "w");
if ( fp ) then
-- fp:read( format );
-- [ *l | *a | *n ]
local t = fp:read("*a");
print(t);
else
print("no file");
end
f = io.open( "test.txt", "r")
out = io.open("out.txt","w")
-- 各行を処理をする
for line in f:lines() do
out:write(line.."\n")
print(line)
end
out:close()
f:close()
Data 型とは [dataをどう扱うか(どう見るか)] の形式
計算機内部では すべての情報は 数値として扱われる.
文字列型 . bit列 を 文字として解釈する.
nil
number
string
boolean
table
function
thread
userdata ( C のメモリブロック )
-- 型をしらべる
local n = "aaa";
print ( type(n) );
number : double( luaconf.h で変更可能 )
usrdata: 任意の C の data を格納する. ( == 生の memblock ) -> ( 代入, 比較 )演算のみ定義
thread : 実行している thread を格納. ( coroutign の実装のために使用 )
Lua Thread と OS Thread は異なる.
table : 連想配列. [ == KEY が数値以外に任意の値がOK ]
table は異種混合可能. ( 関数をおくことも可能 )
この table が Lua での 唯一の data 構造.
record を table を利用して, 表現してみる.
field名 == index として利用する.
a.test == a["test"];
table thread function usrdata の値は参照.
___
■ キャスト(cast)
Luaは文字列と数値を実行時に自動的に変換してくれる。
-- number -> string
c = 10 + 20;
String.print( c );
Number -> 文字列演算 -> String
string -> 数値演算 -> Number
nr = nr + "1";
nr += "35"; -- これはダメらしい.
文字列と数値の結合ができる
-- "number = 10"
"number = " .. 10
WARNING
bool は .. で文字列に cast できない?
str = str .. 10
POINT
C では float -> int では自動的に少数部が切り捨てられる.
Lua では数値という概念しかないので, 切り捨てられることはない.
-- math.abs() の型 chk version を用意する.
function myabs(n)
if(type(n) ~= "number" ) then
print(n);
error("must be a number prm");
end
print(math.abs(n));
end
myabs( "10" );
WARNING
だたし等号をとるときは, 同じ型である必要がある。
if "107" == "107" then
print ( "true" )
end
___
■ 代入演算子 [ = ] の左側にかける[ 式 ]を [ 左辺値 ] という
loadstring("print(_VERSION)")()
loadstring("print(_VERSION)") -- 戻り値は関数.
POINT
戻り値として使用する関数を, 高階関数という.
table を返して, すぐに利用する.
function test()
arr = { 1, 2, 3 };
return arr;
end
do
test()[2] = 10;
print( test()[3] );
end
ユーザーデータにガベージコレクタメタメソッドを設定する. ( hook みたいなもの ? )
使う目的:
[ Lua GC を 外部のリソースに利用ささせる. ]
-> 独自に確保した work を解放する. -> finalizer と呼ばれる.
メタテーブルに __gc フィールドをもつ, usrdata に以下の関数相当のことをする.
function gc_event (udata)
local h = metatable(udata).__gc
if h then
h(udata)
end
end
___
■ Cから実行する。
C < --- lua_toXXX() --- Lua ret = func( x, y );
C --- lua_pushXXX() return Nr; ---> Lua
// cpp
{
lua_getglobal( s, "config" );
lua_getfield( s, -1, "width" );
int v = luaL_checknumber( s, -1 );
}
___
■ 生成
___
■ lua_createtable
SYNTAX
void lua_createtable (lua_State *L, int narr, int nrec);
STACK
[-0, +1, m]
DESC
空のテーブルを作成してスタックに追加。
The new table has space pre-allocated for narr array elements
and nrec non-array elements.
This pre-allocation is useful
when you know exactly how many elements the table will have.
SYNTAX
void lua_setfield (lua_State *L, int index, const char *key);
STACK
[-1, +0, e]
DESC
index で指定したテーブルに key の名前でスタック最上段の値を登録する。
値はポップされる。
table[ key ] = value という設定をする。
Lua の中では, newindex meta method が呼ばれる可能性がある.
Tbl に G を指定すれば, VarGbl にも指定可能.
As in Lua,
this function may trigger a metamethod for the "newindex" event
lua_pushnumber( s, 10 );
lua_setfield( s, -2, "test" );
SYNTAX
void lua_rawgeti (lua_State *s, int idxTbl, int n );
DESC
lua_rawget のキーの値を整数の n に限定した関数。
table[ n ] の結果をスタックへ積む。
( MetaMethod はよばれない )
STACK
[-0, +1, -]
POP
tbl[n];
SYNTAX
void lua_getfield (lua_State *L, int index, const char *k);
desc
index が指す table["k"] の値を stack top へ積む。
key は stack top の値
field 名を指定できるのが point
lua_rawset( s, LUA_ENVIRONINDEX );
POP
KEY の値に対応する VAL
POINT
指定した KEY がない場合は nil を返す。
-->
-------- --------
number
-------- --------
tbl tbl
-------- --------
通常のテーブルと同じだが、
メタテーブルのキーに対して, 関数などを設定することで + などの演算を上書きして
独自の動作をさせることができる
C++ での operator +() と同じ。
Lua の各値はメタテーブルをもつ。
クラスのインスタンスを作ったときに メタテーブルを設定しておくと
+ などで独自の設定ができる。
メタテーブルのキーは getmetatable() でリストできる。
Every value in Lua can have a metatable.
This metatable is an ordinary Lua table that
defines the behavior of the original value
under certain special operations.
You can change several aspects of the behavior of operations over a value
by setting specific fields in its metatable.
For instance,
when a non-numeric value is the operand of an addition,
Lua checks for a function in the field "__add" in its metatable.
If it finds one,
Lua calls this function to perform the addition.
We call the keys in a metatable events and the values metamethods.
In the previous example,
the event is "add" and the metamethod is the function that performs the addition.
You can query the metatable of any value
through the getmetatable function.
You can replace the metatable of tables
through the setmetatable function.
You cannot change the metatable of other types from Lua (except by using the debug library);
you must use the C API for that.
Tables and full userdata have individual metatables
(although multiple tables and userdata can share their metatables).
Values of all other types share one single metatable per type; that is,
there is one single metatable for all numbers, one for all strings, etc.
A metatable controls how an object behaves in arithmetic operations,
order comparisons,
concatenation,
length operation,
and indexing.
A metatable also can define a function to be called
when a userdata is garbage collected.
For each of these operations Lua associates a specific key called an event.
When Lua performs one of these operations over a value,
it checks whether this value has a metatable with the corresponding event.
If so, the value associated with that key (the metamethod) controls
how Lua will perform the operation.
Metatables control the operations listed next.
Each operation is identified by its corresponding name.
The code shown here in Lua is only illustrative;
the real behavior is hard coded in the interpreter
and it is much more efficient than this simulation.
All functions used in these descriptions (rawget, tonumber, etc.) are described in §5.1.
In particular,
to retrieve the metamethod of a given object,
we use the expression
metatable(obj)[event]
___
■ lua_setmetatable
SYNTAX
int lua_setmetatable (lua_State *L, int index);
DESC
index で指定したオブジェクトにスタック最上段のテーブルをメタテーブルとして設定する。
最上段のテーブルはPOPされる。
lua_setmetatable( s, -2 );
SYNTAX
int lua_pcall(lua_State *s, int nrArg, int nrRet, int errfunc);
DESC
Protected Mode で関数をコールする。
エラーがなければ, lua_call と同じ処理。
エラーが発生すると、エラーメッセージをスタックへ積みエラーコードを返す。
errfunc で指定したエラーハンドラー関数があればエラーメッセージを引数に呼ばれる。
スタックトレースなどの追加情報をいれるために使う。
RET
0 : 成功
N : 失敗( lua.h )
POINT
失敗した場合は, lua_pop() する
SYNTAX
void lua_getfenv (lua_State *s, int index);
desc
指定した index の値の環境テーブルをスタックに積む
PUSH
指定 index がさす table
___
■ lua_setfenv
SYNTAX
int lua_setfenv (lua_State *s, int index);
DESC
index が指す値が 関数, thread, userdata ならば, stacktop の
環境テーブルを新しい環境として set する.
POP
stacktop の EnvTable
local v = 0;
function testHook()
print("Debug v = "..v);
end
-- 実行文がよばれる直前に testHook を呼ぶ.
debug.sethook( testHook, "l" );
v = v + 1;
POINT
最終的にスタックは元の状態に戻っている
これは良いプログラミング作法