#author("2019-04-14T00:59:39+09:00","","")
*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)
#ref(http://xn--pckzexbx21r8q9b.net/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文自体あまり良い機能ではないので、このような手段は利用しない方がメンテナンスしやすい。~



トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS