Luaの価値と閉鎖



Luas Upvalue Closure



このサイトの記事はすべてJensenMatchaMeowによるオリジナルです。
[ブログガーデン]から転載元のリンク: http://www.cnblogs.com/JensenCat/p/5112420.html

1.クロージャとは



クロージャー機能をサポートするには、通常、ネストされた関数が必要です。ネストされた関数を実行して親関数のローカル変数の状態を変更することにより、親関数は呼び出し元のコンテキストの状態を保存し、ネストされた関数は状態の変更を変更する責任があります。 (簡単に言えば、関数の入れ子関数をサポートする必要があります)

これがLuaクロージャです:



2.クロージャの役割

以下はJavaクラスです。 getNameメソッドは、クラスオブジェクトのプライベートメンバー変数を取得します

class Person { private String name public String getName() { return name } }

上記の方法で、クラス内のプライベートプロパティを取得できます。同様に、Luaのメソッドを介してこのメ​​ソッドのローカル変数を取得し、このメソッドのメソッドを介して目的の変数値を読み取ることができます。



function func3() local num3 = 44 function func4() return num3 end return func4 end local func = func3() print(func())

説明:

1. func3内のローカル変数は外部から取得できませんが、func3内のローカルメソッドfunc4は取得できるため、 func4への参照を返します 、func3の内部変数は、このfunc4を介して外部から取得できるようにします。

2.円ですが、このような方法で方法の外で内部値を取得します。このメソッドのローカルメソッドfunc4はクロージャと呼ばれます。多くの本の概念によれば、このメソッドはメソッドとメソッドの間にブリッジを構築するため、メソッド内のリソースを外部から任意に取得することもできます。

3.ただし、クロージャによって変数がメモリを永続的に占有するため、パフォーマンスの問題が発生します。簡単に使用しないことをお勧めします。使用したとしても、適切な実際に解放する必要があります。

3.ゲーム開発への応用

- The following uses Lua in cocos2dx as an example... --2dx export class methods through tolua++ --Example API --The format of the button response callback function is: --luaFunc(event) --event is touch press, touch move, touch leave and other events The API in --lua is: --UIButton::addListenHandler(luaFunc) - The actual requirement is that when my button is pressed, I need to change the texture of the button itself... there is no object (sender) of the button itself in the callback at this time. --Easily solved with closures --The following is a practical example of LUA: a page class of testUI local testUI = testUI or {} local testUI:onBtnClick(sender,event) --The available parameters are: hidden self, btn, event end function testUI:initButton() local btn = UIButton:create() --The point is coming btn:addListenHandler( function(event) - Use closures to pass in both self and btn... self:onBtnClick(btn,event) end ) end return testUI

4.lua関数の再帰と末尾呼び出しの削除

1)再帰的な例:

--Reverse recursion example (recursion must be called after initialization) local func = function(n) if n> 0 then return func(n-1) - call error here end - Correct example 1 local func func = function(n) if n> 0 then return func(n-1) - call error here end - Correct example 2 (here the function is expanded to the code of example 1 and then executed) function func(n) if n> 0 then return func(n-1) - call error here end --If it is two functions nested recursion (advance recursion must be declared first) local g local f --Local cannot be added here. Otherwise, it means that there is one more local variable declared, and the recursive object is wrong. function g() f() end --Local cannot be added here. Otherwise, it means that there is one more local variable declared, and the recursive object is wrong. function f() g() end

2)末尾呼び出しの除去(返された関数が再帰中の最後の実行である場合...スタックスペースを消費しません。これはGOTOステートメントと同等です)

--Tail call elimination function g() return a,b end - Correct example function f() return g() - correct tail call elimination end --Error example 1 function f(x) return g() + 1 - the last execution is addition end --Error example 2 function f(x) return (g()) - The last execution is to force return 1 value end --Error example 3 function f(x) return x or g() end function Create(n) local function foo1() print(n) end local function foo2() n = n + 10 end return foo1,foo2 end f1,f2 = Create(1979)--Create closure f1() -- Print 1979 f2() f1() -- Print 1989 f2() f1() -- Print 1999

================================================ == =================

Lua関数は、パラメーターとして渡すことも、結果として返すこともできます。インライン関数は、引き続き関数本体で定義できます。 Luaクロージャは、Lua関数によって生成されたデータオブジェクトです。各クロージャはアップバリュー値を持つことができます。または、複数のクロージャがアップバリュー値を共有します。

upvalueは、クロージャ間のデータ共有メカニズムを提供することもできます。

(1)単層埋め込み関数のクロージャ(関数によって作成されたクロージャ)

関数によって作成されたクロージャは、アップバリューを共有します。

コードは次のように表示されます。

function Test(n) local function foo() local function inner1() print(n) end local function inner2() n = n + 10 end return inner1,inner2 end return foo end t = Test(1979)--Create closure (share an upvalue) f1,f2 = t()--Create closure f1() -- Printing 1979 f2() f1() -- Print 1989 g1,g2 = t() g1() -- Print 1989 g2() g1() -- Print 1999 f1() -- Print 1999

2つのクロージャf1とf2のプロトタイプは、Createのインライン関数foo1とfoo2であり、foo1とfoo2によって参照されるアップバリューは同じであり、Createのローカル変数nです。 Create呼び出しが実行された後、クロージャーはスタック上のnの値をコピーします。したがって、f1とf2にはそれぞれnのコピーがありますか?実際、Luaは、2つのクロージャのアップバリューが現在のスタック上の同じ変数を指していることを検出すると、賢明に1つのコピーのみを生成し、2つのクロージャにコピーを共有させるため、いずれかのクロージャに同じアップバリュー。変更は別の人によって検出されます。上記の例は、これを明確に示しています。f2を呼び出すたびに、upvalueの値が10ずつ増加し、f1が更新された値を出力します。アップバリューのセマンティクスは非常に価値があります。グローバル変数に依存せずにクロージャ間の通信を可能にするため、コードの信頼性が大幅に向上します。

(2)複数の機能が埋め込まれたクロージャ(クロージャによって作成されたクロージャ)

同じクロージャによって作成された他のクロージャは、アップバリューを共有します。

クロージャが作成されると、必要な変数はスタック上になくなりますが、外層のアウトソーシング関数を参照するローカル変数(実際にはアップバリュー)になります。

|_+_|

t = Test(1979)を実行した後、Testのローカル変数nはそのライフサイクルを終了するため、2つのクロージャf1とf2が作成されると、変数nはスタック上にまったく見つかりません。 Test関数のローカル変数nは、fooのアップ値であるだけでなく、inner1とinner2のアップ値でもあります。 t = Test(1979)の後、クロージャーtはnをアップバリューとして保存し、変数nが現在のスタックで見つからない場合、f1とf2は自動的に外側のクロージャー(ここではt)のアップバリューを参照します。アレイ。

G1とg2は、f1とf2と同じアップバリューを共有します。 g1とg2はf1とf2と同じクロージャーtで作成されるため、それらが参照するアップバリュー(変数n)は実際には同じ変数であり、それらのアップバリュー参照はすべて同じ場所を指します。