lua中的类型

基础类型

#define LUA_TNIL		0
#define LUA_TBOOLEAN		1
#define LUA_TLIGHTUSERDATA	2
#define LUA_TNUMBER		3
#define LUA_TSTRING		4
#define LUA_TTABLE		5
#define LUA_TFUNCTION		6
#define LUA_TUSERDATA		7
#define LUA_TTHREAD		8

变体(或者说子类型)

/*
** tags for Tagged Values have the following use of bits:
** bits 0-3: actual tag (a LUA_T* value)
** bits 4-5: variant bits
** bit 6: whether value is collectable
*/

/*
** LUA_TFUNCTION variants:
** 0 - Lua function
** 1 - light C function
** 2 - regular C function (closure)
*/

/* Variant tags for functions */
#define LUA_TLCL	(LUA_TFUNCTION | (0 << 4))  /* Lua closure */
#define LUA_TLCF	(LUA_TFUNCTION | (1 << 4))  /* light C function */
#define LUA_TCCL	(LUA_TFUNCTION | (2 << 4))  /* C closure */


/* Variant tags for strings */
#define LUA_TSHRSTR	(LUA_TSTRING | (0 << 4))  /* short strings */
#define LUA_TLNGSTR	(LUA_TSTRING | (1 << 4))  /* long strings */


/* Variant tags for numbers */
#define LUA_TNUMFLT	(LUA_TNUMBER | (0 << 4))  /* float numbers */
#define LUA_TNUMINT	(LUA_TNUMBER | (1 << 4))  /* integer numbers */


/* Bit mark for collectable types */
#define BIT_ISCOLLECTABLE	(1 << 6)

  lua中的工具都是用TValue来形貌的,TValue中的tt_成员变量代表着这个TValue的类型。关于类型的详细界说,上面贴的代码中的注释中已经讲的对照清楚了。
  一个lua工具的类型是由一个7位的bits形貌的。好比一个整数,这个工具的类型就是0011000(24)示意这个工具是数字类型中的整形,是一个不能接纳工具。

C#若何获取lua工具

  和c语言和lua交互实在没啥本质区别,就是通过lua提供的c函数操作lua栈,直接从栈中取就可以了。区别在于若何把取到的值转换为c#熟悉的值。

若何在C#端形貌这些类型

简介

  lua的类型中boolean、string、number这几个类型是clr所熟悉的类型,以是clr就可以直接把这些类型拿过来用。详细就是直接挪用Lua提供的lua_tonumber之类的c接口。
  lightUserData、table、function、userData、thread是C#不熟悉的类,需要通过某种标识(lua自带的reference系统)来示意。

boolean、string、number类

  这三个类上面已经说过了,直接用提供的接口转就可以,下面写几个需要注重的点:

  1. string虽然也是一个引用类型,然则clr在拿到这个string的指针时,还需要将这个string的数据直接复制进clr中才算转型竣事(xlua也已经封装好了,不用我们自己去复制)。
  2. 大部分类型转型失败的时刻都不会报错,而是会返回一个默认值。就拿将一个lua工具转为int来说,最终是通过lua_tointegerx函数挪用的,当lua工具不是number类型时,返回0:
LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) {
  lua_Integer res;
  const TValue *o = index2addr(L, idx);
  int isnum = tointeger(o, &res);
  if (!isnum)
    res = 0;  /* call to 'tointeger' may change 'n' even if it fails */
  if (pisnum) *pisnum = isnum;
  return res;
}
  1. 当一个number类型是浮点数时,转型整数不会举行取整操作,而是会直接返回0。由于lua默认对float转int的操作模式LUA_FLOORN2I是0,代表遇见float转int时返回0。
/*
** try to convert a value to an integer, rounding according to 'mode':
** mode == 0: accepts only integral values
** mode == 1: takes the floor of the number
** mode == 2: takes the ceil of the number
*/
int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
  TValue v;
 again:
  if (ttisfloat(obj)) {
    lua_Number n = fltvalue(obj);
    lua_Number f = l_floor(n);
    if (n != f) {  /* not an integral value? */
      if (mode == 0) return 0;  /* fails if mode demands integral value */
      else if (mode > 1)  /* needs ceil? */
        f += 1;  /* convert floor to ceil (remember: n != f) */
    }
    return lua_numbertointeger(f, p);
  }
  else if (ttisinteger(obj)) {
    *p = ivalue(obj);
    return 1;
  }
  else if (cvt2num(obj) &&
            luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
    obj = &v;
    goto again;  /* convert result from 'luaO_str2num' to an integer */
  }
  return 0;  /* conversion failed */
}

userData

  userData主要是lua对c#工具的引用,这里只简朴说一下。
  代表c#工具的userData主要分两种。

  1. 把c#工具存在ObjectTranslator中,用下标作为引用(类似于lua中的reference)。
  2. 经由GC优化的结构体和枚举,不存在ObjectTranslator中,而是把所有内容都打包到userdata中一起传入lua中。好比一个Vector3,那么xlua会把这个Vector3的x、y、z作为3个延续的float一起打包到userdata中。这样就避免了c#层的装箱、拆箱和gc操作。

对table与function的引用简介

  这两个类型都是通过lua的reference系统来让c#持有对lua工具的引用。

lua reference系统

  c#就是通过这个系统来持有不熟悉的lua工具的。
  一共就两个接口:

  1. luaL_ref:把栈顶元素加入一个lua的表中,并返回下标。
  2. luaL_unref:把一个下标所代表元素从表中删除。

  这样就可以用一个整数来让lua外的环境持有这个lua工具。
详细可以看下官方说明lua References

luaBase类

  所有lua工具在c#中的基类,在初始化时通过luaL_ref天生lua工具的引用,在析构时通过luaL_unref移除引用。

对table的引用

LuaTable

  一样平常情况下table在C#中被包装为LuaTable类,没啥稀奇的,只是在LuaBase的基础上增加了几个常用的函数。好比Get、Set之类的,让开发者可以避开一些不直观的栈操作。

Array、List、Dictionary

  这几个都差不多。都是把table中的key和value所有拿出来,组成Array或Dictionaray。

接口、其他类

  这两种转型是实验把这个table看作对应的接口或类。
  好比将一个table转为IEnumberator就是把table转为SystemCollectionsIEnumeratorBridge类(继续了LuaBase、实现了IEnumerator的类,由Xlua天生),这个类实现了MoveNext和Reset。实现方式就是挪用一下table中对应名称的函数。

对function的引用

  lua函数在c#中有两种示意:

LuaFunction

  LuaFunction和luaTable差不多,也是在LuaBase的基础上增加了几个常用函数,Call、Action之类的。

DelegateBridge

  为什么已经有LuaFunction还要一个DelegateBridge类?
  由于我们在c#中拿到一个lua函数时,大多数时刻是要作为一个委托来时用的。DelegateBridge就是用来化简这个转型操作的。
  DelegateBridge的功效就是在持有lua函数引用的同时,将这个函数包装成林林总总的委托,让整个转型历程对开发人员无感知。
  下面是一个不使用DelegateBridge,自己转型的例子,对照繁琐:

//将一个LuaFunction作为一个Action<int>使用
//实在LuaFunction.Cast就是干这个的,这里只是用简朴的方式表达出来
public static Action<int> LuaFunctionToActionInt(XLua.LuaFunction luaFunction)
{
    //由于luaFunction已经提供了Call操作封装了函数挪用的种种栈操作,以是我们这里只需要用一个Action<int>把这个操作包装起来即可
    return (x) =>
    {
        luaFunction.Call(x);
    };
}

public static void Test()
{
    XLua.LuaEnv luaEnv = new XLua.LuaEnv();
    object[] rets = luaEnv.DoString("return function(x) CS.UnityEngine.Debug.LogError(\"print x: \"..x) end");
    var luaFunction = (XLua.LuaFunction)rets[0];
    Action<int> actionInt = LuaFunctionToActionInt(luaFunction);
    actionInt(10);
}

DelegateBridge主要成员

xlua在将lua函数转型的时刻做了什么

Tips

  1. 通过ObjectTranslator.getDelegateUsingGeneric天生委托时,会对返回值和参数举行不为值类型的约束。由于值类型在il2cpp下会有jit异常。这也是为什么我们发现有的委托类型不用注册也可以使用,然则有的就不行。
  2. 在编辑器模式下,没有举行代码天生时,会通过Emit直接天生一个XLuaGenDelegateImplx类,内容和通过代码天生后的DelegateBridge一样,而不是所有通过反射来举行转型。让没有举行代码天生时的环境和真机环境更靠近。
  3. DelegateBridge一样平常不会被直接引用,而是被bindto中的委托天生的闭包引用和被delegate_bridges作为弱引用持有。当一个DelegateBridge的bindto中的委托没有被任何工具引用时,这个DelegateBridge就会在下次gc时被gc掉。

其他

  这里主要写了常用lua类型转型的简介和一些要害点。可能不够周全和细节。
  如果有什么错误或者问题可以在下面留言。

,

欧博注册网址

www.cx11gw.cn欢迎进入欧博网址(Allbet Gaming),欧博网址开放会员注册、代理开户、电脑客户端下载、苹果安卓下载等业务。

发布评论

分享到:

欧博网址:【模范伉俪】张晋46岁生日 蔡少芬送祝福:命都畀你
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。