Luaリファレンス 要注意点 ~関数~†
関数の定義は2種類†
関数の定義の2種類の微妙な違い†
- シンタックスシュガー(functionを前に置く書き方)は、
local function foo (<params>) <body> end
↓
local foo
foo = function (<params>) <body> end
と展開されると考えてよい。~
これは事前にfooを宣言しておくことで、
自身の再帰問題(先に宣言が完了していないと未定義となる問題)を避けるため。
逆に、無名関数を変数に代入するやり方だと、
local fact = function (n)
if n == 0 then return 1
else return n*fact(n-1)
end
end
こうなるが、
これは、factの定義が完了しないうちに、factを呼び出しているため、エラーとなる。
一方、
local function foo (<params>) <body> end
とシンタックスシュガーを使った場合は、
local fact
fact = function (n)
if n == 0 then return 1
else return n*fact(n-1)
end
end
と展開されるため、問題はない。
よって、可能な限りシンタックスシュガーを利用するべきである。
関数はfunction型†
名前空間に関数を入れるかのような用法†
無名関数が良く登場するシーン†
- 他のスクリプト言語と同様、sort関数などで無名関数は良く登場する
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 )
関数の( )の省略†
呼び出す側の引数の数は、少なくとも多くともOK†
- 引数の数が多かったり、不足していると、勝手に合わせてくれる。
(正直言って、これはあまり良くない仕様であろう。メリットもあるがデメリットも大きい)
function f(a, b)
return a or b
end
f(3) -- b は nil となる。
f(3,4)
f(3,4,5) -- 5 は 利用されない。
関数とreturn†
複数の値のreturn と ( )†
- return ステートメントで( )を使ってしまうと、値が1つしか返らないので注意!!
function abc(x, y)
return (p(x)) -- p(x)が元来複数の値を返す関数だったとしても、( )をつけることで最初の1つに絞られてしまう。
end
- 複数の返り値を持つ関数を、安易に( )でくくってしまっても同様に値が1つに絞られてしまうので注意
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
複数の値をリストのように返す†
- 複数の値をリストのように返すことが可能。
このあたりは、Perl,Pythonと同じ。特にPythonとほぼ同じ。
function foo() return "a", "b" end
x,y,z = 10, foo() --> 10, "a", "b"
何も返していない関数はnilを返していることと同じ†
function foo() end
x = foo() --> nil 有効な値を返していない関数(return だけ含む)はnilを返した
複数の値を返す関数とテーブルのコンストラクタ†
- 関数をリスト内に配置した時、複数の値を返すのは「リストの最後にある場合のみ」
わかりにくい話なので、具体例で示す。
なぜこのような仕様にしたのか理解に苦しむ、間違いやすい特性だと言える。
function foo()
end
function foo1()
return "a"
end
function foo2()
return "a", "b"
end
という、3つの関数があるとする。
この時、
t = { foo0(), foo2(), 4 }
---> t = {nil, "a", "b", 4} と思うかもしれないが実際にはそうではない、
-- foo2()は「リストの最後」に位置しないので、値はひとつだけ返すので
-- t = {nil, "a", 4 } となる。
一方、
t = { foo0(), 4, foo2() }
---> t = {nil, 4, "a", "b" } はfoo2はリストの最後に位置するので、そのまま複数の値が返される。
複数の値を返す関数を、呼び出す際に1つだけの値としたい場合、( )で囲む†
unpack と 関数の引数†
「...」と可変長引数†
- ...は可変長の「リスト」とみなされる。よって{...}などとすると、このリストを元に配列を作れる。
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
「...」とPerl的な値の渡し方†
「...」の一部を取り出す†
名前付き引数†
末尾呼び出しとスタック†