Lua 5.3-関数をすばやく把握

25132 ワード

Q:Luaではどのように関数を定義して呼び出しますか.
A:
function foo(arg1, arg2, ...)
  dosomething
  return ret1, ret2, ... or nothing
end

-- add all elements of array 'a'.
function add (a)
  local sum = 0
  for i,v in ipairs(a) do
    sum = sum + v
  end
  return sum
end

-- call it.
a = {1, 2, 3, 4}
foo(a)

Q:関数をオブジェクト向けに呼び出すにはどうすればいいですか?
A:o:foo(x)、これはo.foo(o, x)に等しい.
Q:Luaが作成した関数はどのようにして複数の戻り値を返しますか?
A:returnの後ろに何個の値を書けば、関数に何個の値を返すことができますか.
function maximum (a)
  local mi = 1          -- maximum index
  local m = a[mi]       -- maximum value
  for i,val in ipairs(a) do
    if val > m then
      mi = i
      m = val
    end
  end
  return m, mi
end

Q:Luaはどのように関数の戻り値を制御しますか?
A:1、関数を1つの文で呼び出すと、luaは関数のすべての戻り値を無視します(変数受信もないため).
foo()

2、関数が一連の式の最後の式として呼び出されると、luaは関数のすべての戻り値を保持する.この一連の式には、1つの式が複数の変数に値を割り当て、関数のパラメータ伝達、テーブルの構造、および別の関数としての戻り値が含まれます.
function foo() return 'a','b' end    -- returns no results

--             
x, y = foo()    --> x = 'a', y = 'b'
x, y, z = foo()    --> x = 'a', y = 'b', z = nil
x, y, z = 10, foo()    --> x = 10, y = 'a', z = 'b'
x, y, z = foo(), 10    --> x = 'a', y = 10, z = nil -- foo()        ,             。

--        
print(foo())    --> a b
print(1, foo())    --> 1 a b
print(foo(), 1)    --> a 1
--   !        :
print(foo() .. "x")    --> ax
print("x" .. foo())    --> xa --                。
--   :".."         ,foo()             。

--     
a = {1, foo()}    --> a[1] = 1, a[2] = 'a', a[3] = 'b'
a = {foo(), 1}    --> a[1] = 'a', a[2] = 1

--            
function foo1()
  return 5, foo()
end
function foo2()
  return foo(), 5
end
print(foo1())    --> 5 a b
print(foo2())    --> a 5

3、その他の場合、luaは関数の最初の戻り値のみを保持します(いくつかの場合が見られます).
Q:どのようにして制限関数に最初の戻り値だけを返すように強制しますか?
A:使用()」は関数呼び出しを囲み、
function foo() return 'a','b' end

print((foo()))    --> a

Q:可変パラメータ関数の定義と使用方法
A:使用...
--  lua    C    printf()。
function printf(fmt, ...)
  --[[ select (index, ···)
         index     ,          index           。
         index                  index(-1       )。
         ,  index   "#",select()           。]]
  for i = 1, select('#', ...) do    -- select()          。
    --   select()    i           ,         。
    arg[i] = select(i, ...)
  end

  -- string.format()      ;io.write()      。
  return io.write(string.format(fmt, table.unpack(arg)))
end

Q:Luaの関数は「first-class values」で、「first-class values」とは何ですか.
A:数値や文字列などの従来の変数と同じ権限を持ちます.変数に格納してもよいし、テーブルに格納してもよいし、パラメータとして伝達してもよいし、関数の戻り値としてもよい(C言語の「関数ポインタ」にはこれらの特性がある).Luaでは関数は値とみなされ,Luaでいう関数名は実際には関数を格納する変数の名前である.
Q:Luaの関数は“lexical scoping”の特性を持って、何が“lexical scoping”ですか?
A:関数はその関数を包む値にアクセスできます.
function foo()
   a=1
   foo1()    -- foo1()     a。
end

Q:「Proper Tail Calls」とは?
A:「Proper Tail Calls」は、C言語の「goto」呼び出しに似た機能です.1つの関数の最後の動作が別の関数を呼び出す場合、呼び出された関数は「Proper Tail Calls」特性を有する.
--[[ g()  f() "Proper Tail Calls"。   f()    g() ,        f() ,  f()        。              ,                         。]]
function f(x)
  return g(x)
end

Q:「Proper Tail Calls」の実用化?
A:謎解きのゲームです.
function room1 ()
  local move = io.read()
  if move == "south" then return room3()
  elseif move == "east" then return room2()
  else print("invalid move")
       return room1()   -- stay in the same room
  end
end

function room2 ()
  local move = io.read()
  if move == "south" then return room4()
  elseif move == "west" then return room1()
  else print("invalid move")
       return room2()
  end
end

function room3 ()
  local move = io.read()
  if move == "north" then return room1()
  elseif move == "east" then return room4()
  else print("invalid move")
       return room3()
  end
end

function room4 ()
  print("congratulations!")
end

--    room1    。
room1()

south west invalid move east congratulations!
Q:「Closures」とは?
A:匿名関数で、「chunk」を含むローカル変数にアクセスできます.」Closuresは、「lexical scoping」および「Proper Tail Calls」プロパティを使用します.
function newCounter ()
  local i = 0
  --                ,            ,       。
  return function ()
    i = i + 1
    return i
  end
end

c1 = newCounter()           -- c1 is a "closure".
print(c1())  --> 1
print(c1())  --> 2

c2 = newCounter()           -- c2 is another "closure".
print(c2())  --> 1
print(c1())  --> 3
print(c2())  --> 2

Q:「factory」とは?
A:「Closures」の関数を作成します.上のnewCounter()が「factory」です.
Q:「sandbox」とは?
A:「Closures」で作成した安全なlua実行環境を利用する.インターネットから取得したluaプログラムは、ソースコードを読み取る前に、セキュリティが不明であり、内部で危険な実装(プライバシーファイルの読み取り、システムファイルの削除など)があるかどうかは不明です.」Closuresの利点は、匿名関数を含む「chunk」のローカル変数にアクセスできることです.そのため、この特性を利用して敏感な関数を制限し、安全な「sandbox」を作成することができます.
do
  local oldOpen = io.open
  io.open = function (filename, mode)
    --[[ access_OK()             ,              。   access_OK()  "true"        io.open()    。]]
    if access_OK(filename, mode) then
      --            "do-end"      oldOpen。
      return oldOpen(filename, mode)
    else
      return nil, "access denied"
    end
  end
end
-- [[          ,    io.open()     ,
                  "sandbox"    io.open(),
                 io.open(),            io.open(),    。]]

Q:tableに関数を格納する方法
A:
--   table     。
Lib = {
  foo = function (x,y) return x + y end,
  goo = function (x,y) return x - y end
}

--     table      。
Lib = {}
Lib.foo = function (x,y) return x + y end
Lib.goo = function (x,y) return x - y end

--          。
Lib = {}
function Lib.foo (x,y)
  return x + y
end
function Lib.goo (x,y)
  return x - y
end

Q:ローカル関数の作成方法
A:使用localキーワード.
local function f(arg1, arg2, ...)
  dosomething

  return ret1, ret2, ... or nothing
end

Q:ローカルの再帰関数をどのように定義しますか?
A:
--       。
--   1
local fact
fact = function (n)
  if n == 0 then return 1
  else return n*fact(n-1)
  end
end

--   2
local function fact (n)
  if n == 0 then return 1
  else return n*fact(n-1)
  end
end

--       。
local f, g    --          ,         。

function g ()
  ...  f() ...
end

function f ()
  ...  g() ...
end

追加:
1、luaの関数は1つのパラメータしかなく、このパラメータが文字列定数または1つのテーブルの構造である場合、関数呼び出し時に括弧を書かなくてもよい.
print "Hello World"     <--> print("Hello World")
dofile 'a.lua'          <--> dofile ('a.lua')
print [[a multi-line <--> print([[a multi-line message]] message]])
f{x=10, y=20}           <--> f({x=10, y=20})
type{}                  <--> type({})

提案は書いたほうがいいし、規範的で、混乱しにくい.2、関数を呼び出すとき、実パラメータの数が形パラメータの数より多い場合、余分な実パラメータは無視されます.一方、実パラメータの数がパラメータの数より少ない場合、残りのパラメータ値はnilです.
function foo(a, b)
  print(a, b)
end

foo(5, 6, 7)    --> 5 6
foo(5)    --> 5 nil

3、関数returnの式の場合、C言語のように規範のために括弧を付ける必要はありません.
function foo() return 'a','b' end
--        foo()       ,        ,    。
function foo1() return (foo()) end

4、tableでオプションパラメータ関数を実現する.
--[[          ,                           。   table                     ,              。]]
function create_window(options)
  --           ,              。
  if type(options.title) ~= "string" then
    error("no title")
  elseif type(options.width) ~= "number" then
    error("no width")
  elseif type(options.height) ~= "number" then
    error("no height")
  end

  _create_window(options.title,
          options.x or 0,    -- default value is 0
          options.y or 0,    -- default value is 0
          options.width, options.height,
          options.background or "white",   -- default is "white"
          options.border      -- default is false (nil)
         )
end

5、functionが変数によって格納できる値と見なされる以上、変数付与の操作に従って関数を作成し、使用することができる.
foo = function (x) return 2*x end
print(foo(5))    --> 10

6、「Proper Tail Calls」と誤認された場合:
--    g()  ,     g()     return。
function f()
  g()
  return
end

--    g()  ,      。
function f()
  return g() + 1
end

--    g()  ,    "or"  。
function f()
  return x or g()
end

--    g()  ,     g()       。
function f()
  return (g())
end

7、“Closures”の1つの応用、math.sin()は受信角度値に変換され、
do
  local oldSin = math.sin    --    math.sin()     。
  local k = math.pi/180    --        。
  math.sin = function (x)    --   math.sin()     。
    return oldSin(x*k)    --            math.sin()。
  end
end

8、関数を表に保存して管理しやすい.たとえば、関数と必要なデータをtableに格納し、管理全体を形成することができます.9、以下にローカルの再帰関数を定義する方法が間違っている.
local fact = function (n)
  if n == 0 then return 1
  else return n*fact(n-1)   -- buggy
  end
end

Luaが「n*fact(n−1)」をコンパイルする場合、「local fact」はまだ存在しない.そのため、このように書かれた結果は、その「local fact」ではなく、グローバルな「fact」を使用しています.この問題を解決するためには、「Q&A」で述べた正しい方法のように、「local fact」を定義する必要がある.