サーチ…
構文
- funcname = function(paramA、paramB、...)ボディ。 return exprlist end - 単純な関数
- 関数funcname (paramA、paramB、...)本体。 return exprlist end - 上記のための短縮形
- ローカルなfuncname = function(paramA、paramB、...)body; return exprlist end - ラムダ
- ローカルfuncname ; funcname = function(paramA、paramB、...)ボディ。 return exprlist end - 再帰呼び出しを行うことができるラムダ
- ローカル関数funcname (paramA、paramB、...)body; return exprlist end - 上記のための短縮形
- funcname (paramA、paramB、...) - 関数を呼び出す
- local var = varまたは "Default" - デフォルトパラメータ
- return nil、 "エラーメッセージ" - エラーで中止する標準的な方法
備考
関数は通常function a(b,c) ... end
で設定され、まれに変数を無名関数( a = function(a,b) ... end
)に設定すると設定されます。関数をパラメータとして渡すときは逆ですが、匿名関数が主に使用され、通常関数は頻繁には使用されません。
関数の定義
function add(a, b)
return a + b
end
-- creates a function called add, which returns the sum of it's two arguments
構文を見てみましょう。まず、 function
キーワードが表示されます。まあ、それはかなり説明的です。次に、 add
識別子が表示されます。名前。我々は議論(a, b)
見ることができます。これらは何でも構いません。彼らはローカルです。関数本体の内部でのみアクセスできます。最後までスキップしてみましょう...まあ、 end
!その中間にあるのは関数本体です。呼び出されたときに実行されたコード。 return
キーワードは、関数が実際に有用な出力を与えるようにするものです。それがなければ、この関数は何も返しません。これはnilを返すことと等価です。もちろんこれはIOとやりとりするもの、例えば以下のような場合に便利です。
function printHello(name)
print("Hello, " .. name .. "!");
end
その関数では、return文は使用しませんでした。
関数は条件付きで値を返すこともできます。つまり、関数は何も返さない(nil)か値を返すという選択肢があります。これは次の例で実証されています。
function add(a, b)
if (a + b <= 100) then
return a + b -- Returns a value
else
print("This function doesn't return values over 100!") -- Returns nil
end
end
次のように、関数がコンマで区切って複数の値を返すことも可能です。
function doOperations(a, b)
return a+b, a-b, a*b
end
added, subbed, multiplied = doOperations(4,2)
関数はローカル宣言することもできます
do
local function add(a, b) return a+b end
print(add(1,2)) --> prints 3
end
print(add(2, 2)) --> exits with error, because 'add' is not defined here
テーブルに保存することもできます:
tab = {function(a,b) return a+b end}
(tab[1])(1, 2) --> returns 3
関数を呼び出す
関数は、呼び出すことができれば便利です。関数を呼び出すには、次の構文が使用されます。
print("Hello, World!")
私たちはprint
関数を呼び出していprint
。引数"Hello, World"
を使用します。明らかなように、これはHello, World
を出力ストリームに出力します。他の変数と同様に、戻り値にアクセスできます。
local added = add(10, 50) -- 60
変数は、関数のパラメータでも受け入れられます。
local a = 10
local b = 60
local c = add(a, b)
print(c)
表や文字列を期待する関数は、文法的な砂糖を使って呼び出すことができます。呼び出しを囲む括弧は省略できます。
print"Hello, world!"
for k, v in pairs{"Hello, world!"} do print(k, v) end
匿名関数
匿名関数の作成
匿名関数は、名前を持たないことを除けば、通常のLua関数と同じです。
doThrice(function()
print("Hello!")
end)
ご覧のように、この関数はprint
やadd
ような名前には割り当てられません。無名関数を作成するには、名前を省略するだけです。これらの関数は引数を取ることもできます。
構文的な砂糖を理解する
次のコードを理解することが重要です
function double(x)
return x * 2
end
実際には
double = function(x)
return x * 2
end
しかし、関数が直接変数に代入されるので 、上記の関数は匿名ではありません !
関数はファーストクラスの値です
これは、関数が数値や文字列などの従来の値と同じ権限を持つ値であることを意味します。関数は変数、テーブル、引数として渡すことができ、他の関数から返すことができます。
これを実証するために、 "half"関数も作成します:
half = function(x)
return x / 2
end
ですから、 half
とdouble
2つの変数があり、どちらも関数を値として含みます。与えられた2つの関数に数値4を供給し、両方の結果の合計を計算する関数を作成したければどうでしょうか?
sumOfTwoFunctions(double, half, 4)
ようにこの関数を呼びたいと思うでしょう。これはdouble
関数、 half
関数、および整数4
を自分の関数に送ります。
function sumOfTwoFunctions(firstFunction, secondFunction, input)
return firstFunction(input) + secondFunction(input)
end
上記のsumOfTwoFunctions
関数は、関数が引数内でどのように渡され、別の名前でアクセスされるかを示しています。
デフォルトパラメータ
function sayHello(name)
print("Hello, " .. name .. "!")
end
その関数は単純な関数であり、うまく機能します。しかしsayHello()
呼び出すとどうなるでしょうか?
stdin:2: attempt to concatenate local 'name' (a nil value)
stack traceback:
stdin:2: in function 'sayHello'
stdin:1: in main chunk
[C]: in ?
それはまさに素晴らしいことではありません。これを修正するには2つの方法があります:
あなたはすぐに関数から戻ります:
function sayHello(name) if not (type(name) == "string") then return nil, "argument #1: expected string, got " .. type(name) end -- Bail out if there's no name. -- in lua it is a convention to return nil followed by an error message on error print("Hello, " .. name .. "!") -- Normal behavior if name exists. end
デフォルトのパラメータを設定します 。
これを行うには、単純にこの単純な式を使用します
function sayHello(name)
name = name or "Jack" -- Jack is the default,
-- but if the parameter name is given,
-- name will be used instead
print("Hello, " .. name .. "!")
end
イディオムのname = name or "Jack"
はLuaの短絡のために、 or
Luaで短絡して動作します。 or
左側の項目がnil
またはfalse
以外の場合、右辺は決して評価されません。一方、場合sayHello
、その後、パラメータなしで呼び出されたname
になりますnil
、及びその文字列は"Jack"
に割り当てられるname
。 (ブール場合は、このイディオムは、そのため、動作しないことに注意してくださいfalse
問題のパラメータの妥当な値です。)
複数の結果
Luaの関数は複数の結果を返すことができます。
例えば:
function triple(x)
return x, x, x
end
関数を呼び出すときに、これらの値を保存するには、次の構文を使用する必要があります。
local a, b, c = triple(5)
この場合、 a = b = c = 5
となる。また、変数リストの目的の場所で変数_
を使用して、返された値を無視することもできます。
local a, _, c = triple(5)
この場合、2番目に返される値は無視されます。戻り値を変数に代入しないで無視することもできます:
local a = triple(5)
変数a
は最初の戻り値が割り当てられ、残りの2つは破棄されます。
関数によってさまざまな量の結果が返されると、その中の関数を実行することで、それらをすべてテーブルに格納することができます。
local results = {triple(5)}
このようにして、 results
テーブルを反復して、関数が何を返すかを調べることができます。
注意
これは、いくつかのケースでは驚くかもしれません。たとえば、次のようになります。
local t = {}
table.insert(t, string.gsub(" hi", "^%s*(.*)$", "%1")) --> bad argument #2 to 'insert' (number expected, got string)
これは、 string.gsub
が2つの値を返すために発生します。指定された文字列、置換されたパターンの出現回数、発生した一致の総数です。
これを解決するには、次のように中間変数を使用するかput ()
を呼び出します。
table.insert(t, (string.gsub(" hi", "^%s*(.*)$", "%1"))) --> works. t = {"hi"}
これは呼び出しの最初の結果だけを取得し、残りは無視します。
変数の数
名前付き引数
local function A(name, age, hobby)
print(name .. "is " .. age .. " years old and likes " .. hobby)
end
A("john", "eating", 23) --> prints 'john is eating years old and likes 23'
-- oops, seems we got the order of the arguments wrong...
-- this happens a lot, specially with long functions that take a lot of arguments
-- and where the order doesn't follow any particular logic
local function B(tab)
print(tab.name .. "is " .. tab.age .. " years old and likes " .. tab.hobby)
end
local john = {name="john", hobby="golf", age="over 9000", comment="plays too much golf"}
B(john)
--> will print 'John is over 9000 years old and likes golf'
-- I also added a 'comment' argument just to show that excess arguments are ignored by the function
B({name = "tim"}) -- can also be written as
B{name = "tim"} -- to avoid cluttering the code
--> both will print 'tim is nil years old and likes nil'
-- remember to check for missing arguments and deal with them
function C(tab)
if not tab.age then return nil, "age not defined" end
tab.hobby = tab.hobby or "nothing"
-- print stuff
end
-- note that if we later decide to do a 'person' class
-- we just need to make sure that this class has the three fields
-- age, hobby and name, and it will be compatible with these functions
-- example:
local john = ClassPerson.new("John", 20, "golf") -- some sort of constructor
john.address = "some place" -- modify the object
john:do_something("information") -- call some function of the object
C(john) -- this works because objects are *usually* implemented as tables
引数の型のチェック
一部の関数は、特定の型の引数に対してのみ機能します。
function foo(tab)
return tab.bar
end
--> returns nil if tab has no field bar, which is acceptable
--> returns 'attempt to index a number value' if tab is, for example, 3
--> which is unacceptable
function kungfoo(tab)
if type(tab) ~= "table" then
return nil, "take your useless " .. type(tab) .." somewhere else!"
end
return tab.bar
end
これにはいくつかの意味があります。
print(kungfoo(20)) --> prints 'nil, take your useless number somewhere else!'
if kungfoo(20) then print "good" else print "bad" end --> prints bad
foo = kungfoo(20) or "bar" --> sets foo to "bar"
これで、必要なパラメータで関数を呼び出すことができ、プログラムをクラッシュさせません。
-- if we actually WANT to abort execution on error, we can still do
result = assert(kungfoo({bar=20})) --> this will return 20
result = assert(kungfoo(20)) --> this will throw an error
だから、特定のクラスのインスタンスを持つ何かをする関数があればどうでしょうか?これは難しいです。クラスとオブジェクトは通常はテーブルなので、 type
関数は'table'
を返し'table'
。
local Class = {data="important"}
local meta = {__index=Class}
function Class.new()
return setmetatable({}, meta)
end
-- this is just a very basic implementation of an object class in lua
object = Class.new()
fake = {}
print(type(object)), print(type(fake)) --> prints 'table' twice
解決策:メタテーブルを比較する
-- continuation of previous code snippet
Class.is_instance(tab)
return getmetatable(tab) == meta
end
Class.is_instance(object) --> returns true
Class.is_instance(fake) --> returns false
Class.is_instance(Class) --> returns false
Class.is_instance("a string") --> returns false, doesn't crash the program
Class.is_instance(nil) --> also returns false, doesn't crash either
閉鎖
do
local tab = {1, 2, 3}
function closure()
for key, value in ipairs(tab) do
print(key, "I can still see you")
end
end
closure()
--> 1 I can still see you
--> 2 I can still see you
--> 3 I can still see you
end
print(tab) --> nil
-- tab is out of scope
closure()
--> 1 I can still see you
--> 2 I can still see you
--> 3 I can still see you
-- the function can still see tab
典型的な使用例
function new_adder(number)
return function(input)
return input + number
end
end
add_3 = new_adder(3)
print(add_3(2)) --> prints 5
より高度な使用例
function base64.newDecoder(str) -- Decoder factory
if #str ~= 64 then return nil, "string must be 64 characters long!" end
local tab = {}
local counter = 0
for c in str:gmatch"." do
tab[string.byte(c)] = counter
counter = counter + 1
end
return function(str)
local result = ""
for abcd in str:gmatch"..?.?.?" do
local a, b, c, d = string.byte(abcd,1,-1)
a, b, c, d = tab[a], tab[b] or 0, tab[c] or 0, tab[d] or 0
result = result .. (
string.char( ((a<<2)+(b>>4))%256 ) ..
string.char( ((b<<4)+(c>>2))%256 ) ..
string.char( ((c<<6)+d)%256 )
)
end
return result
end
end