*Luaリファレンス 要注意点 ~関数~ [#md26225b]

**関数の定義は2種類 [#mb15204a]
-functionを前に置く書き方(シンタックスシュガー)
#sh(lua){{
function foo (x)
    return 2*x
end
}}

-無名関数を変数に代入する書き方
#sh(lua){{
foo = function (x) return 2*x end
}}
と、ほぼ同じ意味。~
~
**関数の定義の2種類の微妙な違い [#i5e3fb9c]
-シンタックスシュガー(functionを前に置く書き方)は、
#sh(lua){{
local function foo (<params>) <body> end
      ↓
local foo
foo = function (<params>) <body> end
}}
と展開されると考えてよい。~~
これは事前にfooを宣言しておくことで、~
自身の再帰問題(先に宣言が完了していないと未定義となる問題)を避けるため。~
~
逆に、無名関数を変数に代入するやり方だと、
#sh(lua){{
local fact = function (n)
   if n == 0 then return 1
   else return n*fact(n-1)
   end
end
}}
こうなるが、~
これは、factの定義が完了しないうちに、factを呼び出しているため、エラーとなる。~
~
一方、
#sh(lua){{
local function foo (<params>) <body> end
}}
とシンタックスシュガーを使った場合は、~
#sh(lua){{
local fact
fact = function (n)
    if n == 0 then return 1
    else return n*fact(n-1)
    end
end
}}
と展開されるため、問題はない。~
~
よって、可能な限りシンタックスシュガーを利用するべきである。
~

**関数はfunction型 [#l726d311]
-関数はfunction型という変数にすぎないので、テーブルの要素などにすることも問題ない。
#sh(lua){{
abc = { function(x) return x+1 end, 2 }
print(abc[1](3))    --> 4 
}}

**名前空間に関数を入れるかのような用法 [#gf359e08]
-テーブルを名前空間替わりにし、そこに関数を追加していく
#sh(lua){{
Lib = {}

function Lib.foo (x, y) return x+y end
function Lib.goo (x, y) return x+y end
}}
といった記述も可能である。
~

**無名関数が良く登場するシーン [#l69ae55e]
-他のスクリプト言語と同様、sort関数などで無名関数は良く登場する
#sh(lua){{
network = {
    { name = "grauna", IP = "210.26.30.34"},
    { name = "arraial",  IP = "210.26.30.23"},
    { name = "lua",      IP = "210.26.23.12"},
    { name = "gerain",  IP = "210.26.30.20"},
}
table.sort( network, function (a, b) return a.name > b.name end )
}}
~

**関数の( )の省略 [#cde1f2e1]
-引数が1つで、文字列もしくは、テーブルコンストラクタの場合のみ( )を省略可能。~
#sh(lua){{
print "abc"   ---> print("abc")

f{x=10, y=20} ---> f({x=10, y=20})

type{} ---> type({})
}}
~

**呼び出す側の引数の数は、少なくとも多くともOK [#n34d21d4]
-引数の数が多かったり、不足していると、勝手に合わせてくれる。~
(正直言って、これはあまり良くない仕様であろう。メリットもあるがデメリットも大きい)
#sh(lua){{
function f(a, b)
   return a or b
end

f(3)      -- b は nil となる。
f(3,4)
f(3,4,5)  -- 5 は 利用されない。
}}

**関数とreturn [#ldeea1c7]
-C,Perl,Pythonなどと異なり, LUAではreturnを「ブロックの最後]にしか記述出来ない。
#sh(lua){{
function abc(x)
    return             ---->    エラー。ブロックの最後じゃないのにreturnしている。

    print(x)
end
}}
-このため、デバッグ時等で、一時的にreturnしてしまいたい場合は、以下のようにブロック化する。
#sh(lua){{
function abc(x)
    do return end      ---->    OK。

    print(x)
end
}}

**複数の値のreturn と ( ) [#h3bd5bf6]
-return ステートメントで''( )を使ってしまうと、値が1つしか返らないので注意!!''
#sh(lua){{
function abc(x, y)
    return (p(x))   -- p(x)が元来複数の値を返す関数だったとしても、( )をつけることで最初の1つに絞られてしまう。
end
}}
-複数の返り値を持つ関数を、安易に( )でくくってしまっても同様に値が1つに絞られてしまうので注意
#sh(lua){{
function abc(x,y)
    return x+10, y+10     -- 2つの値を返す、関数
end

local a,b = ( abc(1,2) ) -- 安易にカッコでくくると値が最初の1だけになる。a=11, b=nil となってしまう。 

print( abc(1,2) ) --> 11, 12
print( ( abc(1,2) ) ) --> 11
}}

**複数の値をリストのように返す [#c8527815]
-複数の値をリストのように返すことが可能。~
このあたりは、Perl,Pythonと同じ。特にPythonとほぼ同じ。
#sh(lua){{
  function foo() return "a", "b" end
 x,y,z = 10, foo()  --> 10, "a", "b"
}}

**何も返していない関数はnilを返していることと同じ [#s86d40b1]
>>
#sh(lua){{
function foo() end
x = foo()          --> nil  有効な値を返していない関数(return だけ含む)はnilを返した
}}


**複数の値を返す関数とテーブルのコンストラクタ [#a89f8706]
-''関数をリスト内に配置した時、複数の値を返すのは「リストの最後にある場合のみ」''~
わかりにくい話なので、具体例で示す。~
なぜこのような仕様にしたのか理解に苦しむ、間違いやすい特性だと言える。~
#sh(lua){{
function foo()
end

function foo1()
    return "a"
end

function foo2()
    return "a", "b"
end
}}
という、3つの関数があるとする。~
~
この時、
#sh(lua){{
t = { foo0(), foo2(), 4 }
---> t = {nil, "a", "b", 4} と思うかもしれないが実際にはそうではない、
--   foo2()は「リストの最後」に位置しないので、値はひとつだけ返すので
--   t = {nil, "a", 4 } となる。
}}
~
一方、~
#sh(lua){{
t = { foo0(), 4, foo2() }
---> t = {nil, 4, "a", "b" } はfoo2はリストの最後に位置するので、そのまま複数の値が返される。
}}

**複数の値を返す関数を、呼び出す際に1つだけの値としたい場合、( )で囲む [#ca95987b]
- 関数を呼び出したもの全体をカッコで囲うことで、リストは先頭の値1つだけとなる。
#sh(lua){{
function foo2
    return "a", "b", "c"
end

print( (foo2()) )   ---> "a"
}}

**unpack と 関数の引数 [#x7c8f535]
-unpackを使うことにより、配列をリスト化することが可能となる。これはそのまま、関数の引数としても使える。
(Pythonの*[1,2] や*(1,2)などの展開指定と同じ)
#sh(lua){{
function f(a, b)
    return a + b
end

arr = { 1, 2 }

f(unpack(arr))  --> f( 1, 2 )
}}

**「...」と可変長引数 [#n80e048e]
-...は可変長の「リスト」とみなされる。よって{...}などとすると、このリストを元に配列を作れる。
#sh(lua){{
function add (...)
    local s = 0
    for i, v in ipairs{...} do   -- ipairs({...})なので( )は省略可能
        s = s + v
    end
    return s
end

print(add(3,4,10,25,12))    --> 54
}}

-可変数に利用可能という側面だけではなく、~
「複数個所から関数を呼び出している際、そのいずれかに問題があるのではないかとトレースする際に、~
呼び出し側が渡した全ての変数を把握するのに役立つ」~
#sh(lua){{
function foo_check (...)
    print("calling foo:", ...)
    return foo(...)
end
}}

-その他、C言語のprintfや各種言語のsprintf系など、~
可変長引数の関数をラッピングするのにも役立つ。
#sh(lua){{
function fwrite (fmt, ..)
function fwrite (fmt, ...)
   return io.write(string.format(fmt, ...))
end
}}
~

**「...」とPerl的な値の渡し方 [#r347a150]
-このようなことをする必要はないが理解の一環として
#sh(lua){{
function foo (...) 
    local a,b,c = ...
end
}}

**「...」の一部を取り出す [#u3b81f72]
-select(n, ...) で n番目以降の引数をリストとして返す。
-select('#', ...) で全ての総数を返す
#sh(lua){{
for i=1; select('#', ... ) do
    local arg = select(i, ...)   -- i番目のパラメタを取得
     <ループのボディ>
end
}}

**名前付き引数 [#e3e030fd]
--(概ねPerlのhashを使った方法と同じ考え方)
#sh(lua){{
f { old="temp.lua", new="temp1.lua" }  --> f({ old="temp.lua", new="temp1.lua" })  -- ( )内にあるテーブルコンストラクタは( )の省略が可能なのだ

function f (arg)
    --以下のような方法でアクセスが可能である。
    local a = arg.old
    local b = arg.new
end
}}

**末尾呼び出しとスタック [#c1a638ae]
-Luaでは、「return f(x)」のような形でreturn すると~
末尾呼び出し(スタック)排除が成立するため~
スタック積みすぎによるオーバーフローが起きない。~
(スタック積を伴う、call命令ではなく、jmp命令に変換されるため)
#sh(lua){{
function abc(x)
    if (ほげほげ)
        return abc(x)
    end
end
}}

トップ   差分 履歴 リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS