Luaで良く作る文法 ~制御編~

switch

  • switch.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
    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

redo, continue, skip (lua 5.2以上)

  • Lua 5.2にてgoto文が加わったので、これを上手く利用すれば良い。
    但し、ラベルは被ることが許されないので、そこが難点である。
    ::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::
    

continue (Lua 5.1)

  • Lua 5.1系の場合、Lua本体のC言語ソースの修正が許されるならば、以下のパッチを元にソース自体の修正をするのが良いです。 これによって continue文 が使えるようになります。

continue (Luajit 2.0)

  • Luajit 2.0系の場合、Lua本体のC言語ソースの修正が許されるならば、以下のパッチを元にソース自体の修正をするのが良いです。
    Luajit continueの実装
    これによって continue文 が使えるようになります。

3項演算子

  • C++の記述
    // C++の3項目演算
    x = a ? b : c
    

  • Luaの記述
    -- Luaの3項演算っぽい記述方法
    x = a and b or c
    
  • local cond = 3
    local x = cond==3 and "三" or "他"
    print(x)
    

with (Lua 5.2以上)

  • with.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 で名前空間省略を終了します。
    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
Last-modified: 2014-08-16 (土) 19:35:10 (1429d)