*Luaで良く作る文法 ~制御編~ [#tfd3313e] -[[switch>#switch]] -[[redo, continue, skip (Lua 5.2以上)>#lua52_redo_continue_skip]] -[[continue (Lua 5.1)>#lua51_continue]] -[[continue (Luajit 2.x)>#luajit2_continue]] -[[3項演算子>#ternary_operator]] -[[with (Lua 5.2以上)>#lua52_with]] &aname(switch); **switch [#vbd81dc4] - switch.luaとして保存 #sh(lua){{ function switch(c) local swtbl = { casevar = c, caseof = function (self, code) local f if (self.casevar) then f = code[self.casevar] or code.default else f = code.default end if f then if type(f)=="function" then return f(self.casevar,self) else error("case "..tostring(self.casevar).." not a function") end end end } return swtbl end }} -test.lua #sh(lua){{ require "switch" c = 1 switch(c) : caseof { [1] = function (x) print(x,"one") end, [2] = function (x) print(x,"two") end, [3] = 12345, -- エラー default = function (x) print(x,"default") end, } c = "dde" switch(c) : caseof { ['abc'] = function (x) print(x,"c is abc") end, ['def'] = function (x) print(x,"c is def") end, ['ddd'] = 12345, -- エラー default = function (x) print(x,"default") end, } }} -備考~ switch文の疑似実装について、紹介したものの、実際の所は''if ~ elseif~end''でコツコツと記述した方がメンテナンスしやすい。~ switch文の様々な例:[[http://lua-users.org/wiki/SwitchStatement]] &aname(lua52_redo_continue_skip); **redo, continue, skip (lua 5.2以上) [#i0881982] -Lua 5.2にてgoto文が加わったので、これを上手く利用すれば良い。~ 但し、ラベルは被ることが許されないので、そこが難点である。 #sh(lua){{ ::redo1:: for x=1,10 do for y=1,10 do if not f(x,y) then goto continue1 end if not g(x,y) then goto skip1 end if not h(x,y) then goto redo1 end ::continue1:: end end ::skip1:: ::redo2:: for x=1,10 do for y=1,10 do if not f(x,y) then goto continue2 end if not g(x,y) then goto skip2 end if not h(x,y) then goto redo2 end ::continue2:: end end ::skip2:: }} &aname(lua51_continue); **continue (Lua 5.1) [#i0a1afd2] -Lua 5.1系の場合、Lua本体のC言語ソースの修正が許されるならば、以下のパッチを元にソース自体の修正をするのが良いです。 #ref(http://lua.tips/download/grammer/control/lua5.1.continue.patch) これによって continue文 が使えるようになります。~ &aname(luajit2_continue); **continue (Luajit 2.0) [#i0a1afd2] -Luajit 2.0系の場合、Lua本体のC言語ソースの修正が許されるならば、以下のパッチを元にソース自体の修正をするのが良いです。~ [[Luajit continueの実装>https://github.com/sd-/luajit/commit/612f1797554b5dc3f1d64e4755b3fdc4f11b617a]]~ これによって continue文 が使えるようになります。~ &aname(ternary_operator); **3項演算子 [#u01cb885] -C++の記述 #sh(cpp){{ // C++の3項目演算 x = a ? b : c }} ~ -Luaの記述 #sh(lua){{ -- Luaの3項演算っぽい記述方法 x = a and b or c }} - 例 #sh(lua){{ local cond = 3 local x = cond==3 and "三" or "他" print(x) }} &aname(lua52_with); **with (Lua 5.2以上) [#s4aa2ea7] - with.luaとして保存 #sh(lua){{ with = function(...) local ENV = _ENV local mt = getmetatable(ENV) for k=1,select('#',...) do local tbl=select(k,...) local tblmt = getmetatable(tbl) if not mt then setmetatable(ENV,{__index=tbl}) elseif not tblmt then setmetatable(tbl,{__index=mt.__index}); mt.__index=tbl; elseif tbl~=mt.__index then error("bad argument to 'with': metatable already in use") end ENV, mt = tbl, tblmt end end without = function(...) for k=1,select('#',...) do local mt = getmetatable(_ENV) if mt==nil then return end local tbl=select(k,...) local tblmt = getmetatable(tbl) while mt do local index = mt.__index if index == nil then mt=nil elseif index == tbl then mt.__index = (tblmt and tblmt.__index) or nil; mt=nil else mt=getmetatable(index) end end end end }} -test.lua with で 名前空間省略を開始し、without で名前空間省略を終了します。 #sh(lua){{ with(math,string,table) print("sin(1) = "..sin(1)) --> 0.8414709848079 print(format("The answer is %d",42)) --> The answer is 42 print(concat({"with","table","library"}," ")) --> with table library without(string) print(pcall(format,"The answer is %d",42)) --> false attempt to call a nil value }} -備考~ with文の疑似実装を紹介したものの、そもそもwith文自体あまり良い機能ではないので、このような手段は利用しない方がメンテナンスしやすい。~