精华内容
下载资源
问答
  • Unity Lua 之 在 Unity 中 C#访问Lua全局变量、全局 table 和全局 function 的方法 目录 Unity Lua 之 在 Unity 中 C#访问Lua全局变量、全局 table 和全局 function 的方法 一、简单介绍 二、C#访问Lua ...

     Unity Lua 之 在 Unity 中 C#访问Lua 的全局变量、全局 table 和全局 function 的方法

     

    目录

     Unity Lua 之 在 Unity 中 C#访问Lua 的全局变量、全局 table 和全局 function 的方法

    一、简单介绍

    二、C#访问Lua 官网相关知识

    三、注意事项:

    四、实现步骤

    五、关键代码


     

    一、简单介绍

    Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

    xLua为Unity、 .Net、 Mono等C#环境增加Lua脚本编程的能力,借助xLua,这些Lua代码可以方便的和C#相互调用。

    xLua在功能、性能、易用性都有不少突破,这几方面分别最具代表性的是:

    •         可以运行时把C#实现(方法,操作符,属性,事件等等)替换成lua实现;
    •         出色的GC优化,自定义struct,枚举在Lua和C#间传递无C# gc alloc;
    •         编辑器下无需生成代码,开发更轻量;

    在Unity中使用xlua 的重要一个原因就是热更新,我们本着这个歌目的开始我们的学习。

     

    二、C#访问Lua 官网相关知识

    这里指的是C#主动发起对Lua数据结构的访问。 本章涉及到的例子都可以在XLua\Tutorial\CSharpCallLua下找到。

    1. 获取一个全局基本数据类型 访问LuaEnv.Global就可以了,上面有个模版Get方法,可指定返回的类型。

       luaenv.Global.Get<int>("a")
       luaenv.Global.Get<string>("b")
       luaenv.Global.Get<bool>("c")
      
    2. 访问一个全局的table

      也是用上面的Get方法,那类型要指定成啥呢?

      1. 映射到普通class或struct

        定义一个class,有对应于table的字段的public属性,而且有无参数构造函数即可,比如对于{f1 = 100, f2 = 100}可以定义一个包含public int f1;public int f2;的class。 这种方式下xLua会帮你new一个实例,并把对应的字段赋值过去。

        table的属性可以多于或者少于class的属性。可以嵌套其它复杂类型。 要注意的是,这个过程是值拷贝,如果class比较复杂代价会比较大。而且修改class的字段值不会同步到table,反过来也不会。

        这个功能可以通过把类型加到GCOptimize生成降低开销,详细可参见配置介绍文档。 那有没有引用方式的映射呢?有,下面这个就是:

      2. 映射到一个interface

        这种方式依赖于生成代码(如果没生成代码会抛InvalidCastException异常),代码生成器会生成这个interface的实例,如果get一个属性,生成代码会get对应的table字段,如果set属性也会设置对应的字段。甚至可以通过interface的方法访问lua的函数。

      3. 更轻量级的by value方式:映射到Dictionary<>,List<>

        不想定义class或者interface的话,可以考虑用这个,前提table下key和value的类型都是一致的。

      4. 另外一种by ref方式:映射到LuaTable类

        这种方式好处是不需要生成代码,但也有一些问题,比如慢,比方式2要慢一个数量级,比如没有类型检查。

    3. 访问一个全局的function

      仍然是用Get方法,不同的是类型映射。

      1. 映射到delegate

        这种是建议的方式,性能好很多,而且类型安全。缺点是要生成代码(如果没生成代码会抛InvalidCastException异常)。

        delegate要怎样声明呢? 对于function的每个参数就声明一个输入类型的参数。 多返回值要怎么处理?从左往右映射到c#的输出参数,输出参数包括返回值,out参数,ref参数。

        参数、返回值类型支持哪些呢?都支持,各种复杂类型,out,ref修饰的,甚至可以返回另外一个delegate。

        delegate的使用就更简单了,直接像个函数那样用就可以了。

      2. 映射到LuaFunction

        这种方式的优缺点刚好和第一种相反。 使用也简单,LuaFunction上有个变参的Call函数,可以传任意类型,任意个数的参数,返回值是object的数组,对应于lua的多返回值。

    4. 使用建议

      1. 访问lua全局数据,特别是table以及function,代价比较大,建议尽量少做,比如在初始化时把要调用的lua function获取一次(映射到delegate)后,保存下来,后续直接调用该delegate即可。table也类似。

      2. 如果lua测的实现的部分都以delegate和interface的方式提供,使用方可以完全和xLua解耦:由一个专门的模块负责xlua的初始化以及delegate、interface的映射,然后把这些delegate和interface设置到要用到它们的地方。

     

    三、注意事项:

    1、获取 Lua 中的全局变量的时候,注意数据类型要对上,不然可能获取不到正确的全局变量数据

    2、在使用 class 获取 table 的时候,好像获取不到里面的函数(不知道就是这样,还是能获取到,只是方法不对)

    3、在使用 interface 获取 table 的时候,注意 在 interface 前添加上 public(例如 public interface IPerson{}),不然可能会报访问不到

    4、在使用 class 获取 table 的时候,修改值不会映射会lua中;而在使用 interface 获取 table 的时候,修改值会映射会lua中

    5、注意 xlua (版本2.1.14)实话也不是很兼容 Unity 2018.4.12f1 调用 [CSharpCallLua] 会报错,报找不到

    (如果你也有这样可以使用 Unity 2017.4.0f1 版本,测试可用)

    6、使用 Delegate 获取 Lua 全局函数的时候,可以使用 ref 和 out  接受 lua 中多余的返回值

    7、获取全局函数的时候,获取的函数变量, 函数变量使用完建议置空,需要反复使用,可以最后在把函数 = null

     

    四、实现步骤

    1、新建一个文本文件 CSharpGetLuaGlobalParamFunc.lua.txt

     

    2、打开编写 lua 代码

     

    3、新建 Unity 工程,新建一个 LuaTxt 文件夹,并把 文本文件 CSharpGetLuaGlobalParamFunc.lua.txt 导入

     

    4、在工程中,新建脚本实现 C# 访问 Lua 的功能

     

    5、把脚本挂载到场景中

     

    6、运行场景,效果如下,获取到 Lua 中的属性和方法

     

    五、关键代码

    1、CSharpGetLuaGlobalParamFunc.cs

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using XLua;
    
    public class CSharpGetLuaGlobalParamFunc : MonoBehaviour
    {
        // Lua 环境变量参数
        LuaEnv luaEnv;
    
        // Start is called before the first frame update
        void Start()
        {
            LuaInit();
    
            luaEnv.DoString("require'CSharpGetLuaGlobalParamFunc'");
    
            GetLuaGlobalParameters();
            GetLuaGlobalTable_Method_Class();
            GetLuaGlobalTable_Method_Interface();
            GetLuaGlobalTable_Method_Dictionary_List();
            GetLuaGlobalFunction_Method_Delegate();
            GetLuaGlobalFunction_Method_LuaFunction();
        }
    
        /// <summary>
        /// 获取 Lua 全局变量
        /// </summary>
        void GetLuaGlobalParameters() {
    
            // 一定要注意类型,不然可能获取不到正确的值哈
            float numberFloat = luaEnv.Global.Get<float>("numberFloat");
            int numberInt = luaEnv.Global.Get<int>("numberInt");
            string stringData = luaEnv.Global.Get<string>("stringData");
            bool isTrue = luaEnv.Global.Get<bool>("isTrue");
    
            Debug.Log("numberFloat:" + numberFloat);
            Debug.Log("numberInt:" + numberInt);
            Debug.Log("stringData:" + stringData);
            Debug.Log("isTrue:" + isTrue);
        }
    
    
        #region Get Table Class
        /// <summary>
        /// 使用 Class 获取 Table 的内容
        /// 前提:定义一个和 Table 对应的 Class 类
        /// (好似 函数获取不到)
        /// </summary>
        void GetLuaGlobalTable_Method_Class() {
    
            Person person = luaEnv.Global.Get<Person>("person");
            Debug.Log("GetLuaGlobalTable_Method_Class :");
            Debug.Log("name:" + person.name + " age:" + person.age);
            // 修改的值不会映射到 lua 里面
            person.age = 20;
            luaEnv.DoString("print(person.age)");
            // class 方法获取好似获取不到函数
            person.work(1, 2);
        }
    
        /// <summary>
        /// 与 Lua table 对应的 class 类
        /// </summary>
        class Person
        {
            public string name;
            public int age;
            public void work(float a, float b) { }
        }
    
        #endregion
    
        #region Get Table Interface
    
        /// <summary>
        /// 与 Lua table 对应的 interface,请加上[CSharpCallLua] 修饰,并设置为 public 属性
        /// </summary>
        [CSharpCallLua]
        public interface IPerson
        {
            string name { get; set; }
            int age { get; set; }
            void work(float a, float b);
        }
    
        /// <summary>
        /// 使用 Class 获取 Table 的内容
        /// 前提:定义一个和 Table 对应的 interface 类
        /// </summary>
        void GetLuaGlobalTable_Method_Interface()
        {
            IPerson person = luaEnv.Global.Get<IPerson>("person");
            Debug.Log("GetLuaGlobalTable_Method_Interface :");
            Debug.Log("name:" + person.name + " age:" + person.age);
            // 修改的值会映射到 lua 里面
            person.age = 20;
            luaEnv.DoString("print(person.age)");
            // 执行函数
            person.work(1, 2);
            
        }
    
        #endregion
    
        #region Get Table Dictionary、List
        /// <summary>
        /// 使用 Dictionary、List 获取 Table 内容
        /// </summary>
        void GetLuaGlobalTable_Method_Dictionary_List() {
    
            // 获取有变量的值
            Dictionary<string, object> dic = luaEnv.Global.Get<Dictionary<string, object>>("person");
            Debug.Log("Dictionary:");
            foreach (string key in dic.Keys)
            {
                Debug.Log(key + ":" + dic[key]);
            }
    
            // 获取到 单一的值
            List<object> list = luaEnv.Global.Get<List<object>>("person");
            Debug.Log("List:");
            foreach (object item in list)
            {
                Debug.Log(item);
            }
    
        }
        #endregion
    
        #region Get Function Delegate
    
        /// <summary>
        /// 定义与lua 全局函数 对应的 delegate
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="out_a"></param>
        /// <param name="out_b"></param>
        /// <returns></returns>
        [CSharpCallLua]
        public delegate float Sub(float a, float b, out float out_a, out float out_b);
    
        /// <summary>
        /// 使用 Delegate 获取 Lua 全局函数
        /// 前提:定义一个与之对应的 delegate
        /// </summary>
        void GetLuaGlobalFunction_Method_Delegate() {
            Debug.Log("GetLuaGlobalFunction_Method_Delegate:");
            Sub sub = luaEnv.Global.Get<Sub>("sub");
            float out_a, out_b;
    
            // 可以使用 ref 和 out  接受 lua 中多余的返回值
            float ret = sub(3.7f, 1.9f, out out_a, out out_b);
            Debug.LogFormat("ret:{0},out_a:{1},out_b:{2}", ret, out_a, out_b);
    
            // 函数使用完建议置空,需要反复使用,可以最后在把函数 = null
            sub = null;
    
        }
        #endregion
    
        #region Get Function LuaFunction
        /// <summary>
        /// 使用 LuaFunction 获取 lua 全局函数
        /// </summary>
        void GetLuaGlobalFunction_Method_LuaFunction(){
            Debug.Log("GetLuaGlobalFunction_Method_LuaFunction:");
            LuaFunction sub = luaEnv.Global.Get<LuaFunction>("sub");
            object[] rets = sub.Call(4,6);
            foreach (var item in rets)
            {
                Debug.Log(item);
            }
    
            // 函数使用完建议置空,需要反复使用,可以最后在把函数 = null
            sub = null;
        }
    
    
        #endregion
    
        void OnDestroy() {
            LuaDispose();
        }
        
        /// <summary>
        /// Lua 环境初始化
        /// </summary>
        private void LuaInit() {
            luaEnv = new LuaEnv();
        }
    
        /// <summary>
        /// Lua 环境释放
        /// </summary>
        private void LuaDispose() {
            luaEnv.Dispose();
        }
    
        
    }
    

     

    2、CSharpGetLuaGlobalParamFunc.lua.txt

    numberFloat = 20.05
    numberInt = 5
    stringData = "Hello Lua"
    isTrue = false
    
    person={
    	name = "Lua",
    	age = 18,
    	work=function(self,a,b)
    		print("Lua 工作:" + (a+b))
    	end
    }
    
    function sub(a,b)
    	print(a-b)
    	return a-b,a,b
    end

     

    展开全文
  • Lua中的 默认为全局变量,局部变量使用 local 在函数 if for 中定义的也是全局变量 在语句内部输出局部变量可以、但是在外部即无法输出 总结:带有 local 的全为 局部,not local 的即为全局

    Lua中的 默认为全局变量,局部变量使用 local
    在函数 if for 中定义的也是全局变量
    在语句内部输出局部变量可以、但是在外部即无法输出
    总结:带有 local 的全为 局部,not local 的即为全局

    在这里插入图片描述

    展开全文
  • Lua中,要声明全局变量很简单,那就是定义变量的时候,前面不要加上local。 这个神秘的全局变量,其实本质上也是一个table,它把我们创建的全局变量都保存到一个table里了。 而这个table的名字是:_G 我们来...

    本文转载于:http://www.benmutou.com/archives/1781

    1.全局变量的原形

    在Lua中,要声明全局变量很简单,那就是定义变量的时候,前面不要加上local。

    这个神秘的全局变量,其实本质上也是一个table,它把我们创建的全局变量都保存到一个table里了。

    而这个table的名字是:_G

     

    我们来看看代码:

      -- 定义一个全局变量
        gName = "哎哟,很挫哦";
       
        -- 用三种方式输出变量的值
        print(gName);
        print(_G["gName"]);
        print(_G.gName);

    输出结果如下:

    [LUA-print] 哎哟,很挫哦
    [LUA-print] 哎哟,很挫哦
    [LUA-print] 哎哟,很挫哦

    我们定义了一个全局变量gName,于是这个gName成为了_G的一个字段。

    怎么样,很简单吧。

     

    2.非全局的环境

    对于全局变量,不管到了哪个地方,哪种语言,大家总是会告诫说:“不要滥用,后果自负”

    也许是因为这样,所以Lua有了一种比较特殊的机制:非全局环境。

    我称它为“不会造成全局影响的全局变量”。

     

    3.改变函数的全局变量环境——setfenv函数

    先看看以下代码:

     -- 定义一个全局变量
        gName = "哎哟,很挫哦";
       
        -- 将当前全局环境重新设置为新的table
        setfenv(1, {});
       
        -- 输出值
        print(gName);

    如果现在运行代码,输出结果将会是这样的:

    [LUA-print] LUA ERROR: [string “src/main.lua”]:107: attempt to call global ‘print’ (a nil value)

    为什么?很出乎意料的脸print函数都无法找到了?

    这是因为我们已经把当前函数范围内的全局变量环境改变了,全局变量默认是保存在_G中的,而现在的全局变量是在一个新的table里。

    目前这个table是空的,所以不存在任何全局变量。

     

    setfenv函数就是用来改变某个函数范围里的全局环境的,通俗地说,就是把某个函数范围内的_G给弄没了。

     

    setfenv函数两个参数分别代表:

    1). 第一个参数,可以是即将要改变环境的函数,也可以是一个数字。数字1代表当前函数,数字2代表调用当前函数的函数,后面以此类推。

    2).第二个参数,新的全局环境table。

     

    4.保留原来的_G

    现在连print函数都无法使用了,对于测试很不方便,我们可以做个小动作,把原来的_G保留起来。

    如下代码:

     -- 定义一个全局变量
        gName = "哎哟,很挫哦";
       
        -- 将当前全局环境重新设置为新的table
        setfenv(1, {g = _G});
       
        -- 输出值
        g.print(gName);
       
        -- 再次定义一个全局变量
        gName = "哎哟,有点错哦";
       
        -- 再次输出值
        g.print(gName);
       
        -- 输出原来的值
        g.print(g.gName);

    只要在定义新的环境时,把_G作为一个字段放到新的table里,就可以调用原来的全局变量了。

    那么,输出结果如下:

    [LUA-print] nil
    [LUA-print] 哎哟,有点错哦
    [LUA-print] 哎哟,很挫哦

    三次调用g.print函数的输出结果都是不一样的:

    a.第一次,此时刚刚重新设置了全局环境,这时候当前函数的全局变量只有一个,那就是g,所以gName的值是nil。

    b.第二次,我们再一次对gName进行赋值,此时,已经在新的环境中了,所以接下来输出的gName值是存在的。

    c.第三次,这次输出的是g.gName的值,通过g调用的gName值是原先的全局环境里的值,所以gName的值仍然是最初的“哎哟,很挫哦”。

     

    其实,这有什么用呢?倒不如直接用局部变量好了。

    确实,从这例子里看不出什么特别的地方。

    书里对于知识的介绍都是由浅入深的,所以这里暂时也没有更深入的介绍,看到后面内容的时候,我再继续和大家分享。

     

    5.使用__index元方法保留原来的_G

    这里还有一个小技巧分享一下,刚刚举例保留_G,但是调用print等函数时还需要形如g.print的方式,有点碍事。

    我们可以利用__index来解决这个问题,如下代码:

    -- 定义一个全局变量
        gName = "哎哟,很挫哦";
       
        -- 一个table,即将成为新的环境
        local newG = {};
        setmetatable(newG, {__index = _G});
       
        -- 将当前全局环境重新设置为新的table
        setfenv(1, newG);
       
        gName = "别再哎哟了,很烦!";
       
        -- 输出值
        print(gName);
        print(_G.gName);

    我们给新的table设置一个元表,这个元表的__index元方法就是_G。

    于是,当新的环境里找不到print字段时,就会去_G里寻找。

     

    输出结果如下

    [LUA-print] 别再哎哟了,很烦!
    [LUA-print] 哎哟,很挫哦

    第一次输出的是新环境里的gName值,第二次输出的是原来环境里的gName值,互不影响。

     

    6.结束

    好了,关于全局变量和非全局环境,就暂时说这么多。

    虽然暂时还感觉不到有什么作用,没关系,后面还会有关于这部分的内容。

    就像__index一样,是基础,后面可能会经常提到。

    转载于:https://www.cnblogs.com/guangyun/p/4685353.html

    展开全文
  • 我们知道lua脚本语言的变量是弱类型的,即变量没有类型,值才有类型,同一名称的变量具体类型要看所赋值的类型,如下 a=1 --整型 a=1.0 --浮点型 ...全局变量:顾名思义,其生命有效期是全局的,整个lua

    我们知道lua脚本语言的变量是弱类型的,即变量没有类型,值才有类型,同一名称的变量具体类型要看所赋值的类型,如下

    a=1    --整型
    a=1.0  --浮点型
    a="ab" --string型 
    a={}  --table型
    a=function() ... end --function

    全局变量和局部变量,类似于shell脚本
    全局变量:顾名思义,其生命有效期是全局的,整个lua文件中都可以使用,可以在任意地方定义(函数参数除外),但有个原则,使用时必须是先定义好的,否则就是nil,请看下面的代码

    print(i);
    function test(j)
       i = 1;
    end
    test(); --如果不执行test(), i未定义,都是nil
    print(i,j);

    执行结果是

    nil
    1   nil

    局部变量:只在某些特定的范围内有效的变量,称为局部变量,用local修饰。最主要的局部变量是定义在函数内部的局部变量。请看下面的代码片段

    local j=2; --虽然是定义的local变量,但却是在函数外部,
               --所以其作用域是它之后的整个文件,所以等同于全局变量
    function test()
       local i = 1; --局部变量,只在test函数内部有效
       print("j="..j);
    end
    test();
    print(i,j);

    执行结果为:

    j=2
    nil 2

    函数闭包
    函数闭包:闭包(closure),通过调用含有一个内部函数加上该外部函数持有的外部局部变量(upvalue)的外部函数(就是工厂)产生的一个实例函数
    闭包组成:外部函数+外部函数创建的upvalue+内部函数(闭包函数)
    这里,test是外部函数, local i是upvalue, function() i=i+1.. 是内部函数

    function test()
            local i=0   --局部变量
            return function() --尾调用,即尾部调用,将另一函数作为function类型返回
                i = i+1
                return i
            end
        end
        c1=test()
        c2=test(); --c1,c2是建立在同一函数,同一局部变量的不同实例上的两个不同的闭包
                --闭包中的upvalue各自独立,调用一次test()就会产生一个新的闭包
        print(c1()) -->1
        print(c1()) -->2//重复调用时每一个调用都会记住上一次调用后的值,就是说i=1了已经被记住了
        print(c2())    -->1//闭包不同所以upvalue不同    
        print(c2()) -->2

    函数嵌套,即函数内部定义了另一个函数,注意不是函数调用。因为lua将函数也看成是一种基本数据类型,可以用来做赋值和返回。实际也是秉承了c语言指针概念的基础上做的转换,将函数的地址作为基本数据类型(个人理解,不确定正确,待考证)。

    非局部变量,即上面提到的upvalue,这个值改如何理解,如果你有C语言基础,我们不妨先将它理解为函数内部定义的“静态(static)变量”,但upvalue它有自己的特点。

    首先看upvalue的定义要求,一定是外部函数定义的的local局部变量,且在内部函数调用过。如下图中 j n k都是upvalue, 而h由于在内部函数中未调用,所以不是upvalue。(全局变量的作用域是全局的,所以谈论全局变量做upvalue无意义)

    function newCounter() --外部函数
        local j = 0; local n = 0;
        local k = 0; local h = 0;
        print("f1:",j,k,n);     --cd1
        return function() --内部函数
            print("f2:",j,k,n); --cd2
            j = n;
            k = n;
            n = n+1;
            return j,k,n;
        end
    end
    counter = newCounter(); --cd3
    print("f3:",counter()); --cd4
    print("----------分割线----------");
    print("f4:",counter()); --cd5

    执行结果

    f1: 0   0   0
    f2: 0   0   0
    f3: 0   0   1
    ----------分割线----------
    f2: 0   0   1
    f4: 1   1   2

    说明:cd3(code3)将函数赋值给counter,产生一个新实例,即生成一个闭包。从结果看cd4和cd5两次调用counter, 但外部函数的cd1只执行了一次,所以可以看出,闭包函数的外部函数部分只在第一次调用时执行,后面再次时调用直接跳到内部函数执行,所以upvalue的j k n的值只在第一次由外部函数初始化给定,后续的值仍然以某种形式“存活”下来,因此这个特性有点类似于c语言的静态变量。

    如果上面的嵌套函数再次赋值给counter1,则会生成一个新的闭包实例,它和之前的counter之间是相互独立的关系,我们看下面的代码

    function newCounter()
        local j = 0;local n = 0;local k = 0; local h = 0;
        print("f1:",j,k,n);
        return function()
            print("f2:",j,k,n);
            k = n;
            j = n;
            n = n+1;
            return j,k,n;
        end
    end
    
    counter = newCounter();
    print("f3:",counter());
    print("----------分割线----------");
    print("f4:",counter());
    
    print("**********分割线**********");
    
    counter1 = newCounter();
    print("f5:",counter1());
    print("----------分割线----------");
    print("f6:",counter1());

    执行结果:

    f1: 0   0   0
    f2: 0   0   0
    f3: 0   0   1
    ----------分割线----------
    f2: 0   0   1
    f4: 1   1   2
    **********分割线**********
    f1: 0   0   0
    f2: 0   0   0
    f5: 0   0   1
    ----------分割线----------
    f2: 0   0   1
    f6: 1   1   2

    说明: * * * * * * *分割线 * * * * * * *,上面是counter的执行结果,下面是counter1的,两次执行结果一样,证明counter和counter1之间是独立的。我们可以借助c++的概念来理解,将闭包函数看做是创建类(class)的实例,counter和counter1分别是相同类(class)的两个实例,之间没有关联关系,而upvalue则是对应的实例成员函数内部的静态变量。

    upvalue非局部变量可以使用debug.getupvalue和debug.setupvalue来获取和设置,具体函数说明如下:

    • getupvalue (f, up):此函数返回函数 f 的第 up 个上值的名字和值。 如果该函数没有那个上值,返回 nil 。 以 ‘(’ (开括号)打头的变量名表示没有名字的变量 (去除了调试信息的代码块)
    • setupvalue (f, up, value):这个函数将 value 设为函数 f 的第 up 个上值。 如果函数没有那个上值,返回 nil 否则,返回该上值的名字

    这里补充一点up的排序规律,我们看下面的代码

    function newCounter()
        local j = 0;local n = 0;local k = 0; local h = 0;
        local l=0;
        print("f1:",j,k,n);
        return function()
            print("f2:",j,k,n);
            l = n;
            h = n;
            k = n;
            j = n;
            n = n+1;
            return j,k,n;
        end
    end
    counter = newCounter();
    local i = 1;
    print("-----------------------");
    repeat
       name, val = debug.getupvalue(counter, i);
       if name then
           print("index", i, name, "=", val);
           if(name == "n") then
                debug.setupvalue(counter, 2, 10);
            end
            i = i + 1;
        end
    
    until not name
    
    print("-----------------------");
    print("f3:",counter());
    

    执行结果如下:

    f1: 0   0   0
    -----------------------
    index   1   j   =   0
    index   2   k   =   0
    index   3   n   =   0
    index   4   l   =   0
    index   5   h   =   0
    -----------------------
    f2: 0   10  0
    f3: 0   0   1

    从结果上看upvalue的顺序和内部函数return的顺序有关,return 前的排在前面(j k n),没有return的排在后面,且按照调用顺序排列(l h)。

    补充一下闭包定义的两种写法:

    --写法1
    function f1(n)
        --local i=0;
       return function()
           print(n);
           return n;
        end
    end
    
    
    g1=f1(200);
    print(g1()); --如果写成g1(300),带入的参数会被忽略
    
    --写法2
    function f3(n)
        local i=0;
       function f4()
           print(n);
           return n;
        end
        return f4;
    end
    
    g2=f3(200);
    print(g2());
    

    好了,以上这些就是我个人的理解,有不对的请指正,谢谢!

    展开全文
  • 全局变量与局部变量的使用 全局变量即使声明在函数方法里面,只要该方法被调用过,便可在方法外访问到该变量 局部变量的销毁是在语句块的结束 do a=10 local b=20 print(a,b) end print(a,b) &gt;lua...
  • 这个系列我们主要学习...在Lua中,要声明全局变量很简单,那就是定义变量的时候,前面不要加上local。这个神秘的全局变量,其实本质上也是一个table,它把我们创建的全局变量都保存到一个table里了。 而这个tabl..
  • 深入理解Lua全局变量_G以及源码实现  在Lua脚本层,Lua将所有的全局变量保存在一个常规的table中,这个table被称为全局环境,并且将这个table保存在一个全局变量_G中,也就是说在脚本中可以用_G获取这个全局...
  • Lua脚本语言的变量是弱类型的,即...全局变量:顾名思义,其生命有效期是全局的,整个lua文件中都可以使用,可以在任意地方定义(函数参数除外),但有个原则,使用时必须是先定义好的,否则就是nil,请看下面的代...
  • -- 定义全局变量 testNumber = 100 testBool = true testFloat = 1.1111 testString = "str3" -- 本地变量无法通过C# 调用 local num = 200 using UnityEngine; public class CallVariable : MonoBehaviour { ...
  • 04,Lua 全局变量

    2017-06-16 23:24:02
    Lua 全局变量
  • (一)获取lua文件中的简单变量的全局变量 注意,get方法只能获取lua文件里的全局变量,获取不到局部变量 主lua文件代码: print("主lua脚本启动") --整个文件算所有lua文件的主入口 --只要执行lua文件,xlua都会去...
  • //C# 调用Lua using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using XLua; //自定义委托(多个返回数值的函数) //自定义委托(使用out关键字) [CSharpCallLua] ...
  • Lua全局变量

    2020-01-28 17:58:04
    全局变量 在默认情况下,变量总是认为是全局的。 全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。 >print(b) nil >b=10 ...
  • lua中声明一个全局变量很简单 a=5 直接赋值就可以,而且也不会限制变量的类型,我们可以直接把number类型的变量赋值string a="Hello" 声明一个局部变量需要在前面加上关键字 local local b=10 局部变量在当前...
  • Lua中,要声明全局变量很简单,那就是定义变量的时候,前面不要加上local。 这个神秘的全局变量,其实本质上也是一个table,它把我们创建的全局变量都保存到一个table里了。 而这个table的名字是:_G 我们来看看...
  • lua全局变量

    2013-04-25 21:05:00
    全局变量不需要声明,虽然...因为Lua所有的全局变量都保存在一个普通的表中,我们可以使用metatables来改变访问全局变量的行为。 第一个方法如下: setmetatable(_G, { __newindex = function (_, n) ...
  • Lua定义一个context table lua_newtable(L); for (int i = 0; i < 3; i++) { lua_pushinteger(L, i +1);//set key lua_pushinteger(L, i);//set value lua_settable(L, -3); //push key,value } lua_...
  • Lua 全局变量

    2016-01-12 15:15:25
    Lua变量无需先声明(定义)才能使用,如果你要使用某个变量,直接使用就可以了。 未赋值的变量的值是nil。print(b) --> nil b = 10 print(b) --> 10如果你将一个变量手动赋值为nil,则会对该变量进行内存回收。b ...
  • C++获取Lua全局变量和执行Lua多参数多返回值函数
  • 最近在写lua脚本时碰到了一个坑,成功使我fishing一下午。。 举例: 2个lua文件 A B , B类继承A类 A类: function A:func1() ... end A.item1 = { ["item"] = self.func1 } function A:func2() ... ...
  • 由于lua里面随手怎么的写少一个local啥的,就可以轻松创造出一个全局变量来,导致这种定义全局变量的问题挺容易发生的,尤其是在一个代码量比较大的项目里,一人一个,就挺稳的了。 那么为了尽量查找和解决这样的...
  • lua全局环境变量_G小结

    千次阅读 2016-10-07 21:43:08
    1.以一个模块(*.lua,后同)为单位,所有的全局变量都保存在table中,这个table放在_G中,这是一个全局空间(全局环境变量),可以简单的看作一个表。 2._G中只保存全局变量,不保存局部变量。 3.lua中真正存储全局...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,959
精华内容 3,983
关键字:

lua定义全局变量