前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Lua类型系统详解(一)

Lua类型系统详解(一)

作者头像
用户4766018
发布2022-08-19 10:07:14
9100
发布2022-08-19 10:07:14
举报
文章被收录于专栏:格物致知格物致知

Lua是一种动态类型的脚本语言,意味着变量没有类型,类型信息包含在值中。目前lua支持八种基本类型:nil,boolean,number,string,table,function,userdata,thread。所有的值都是第一类值,都是可以存储在变量中或者作为函数参数传递,以及作为函数返回值。

代码语言:javascript
复制
/*
** basic types
*/
#define LUA_TNONE		(-1)

#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

#define LUA_NUMTYPES		9

源码中实际定义了九种类型,其中 LUA_TLIGHTUSERDATA 与 LUA_TUSERDATA统称为userdata,lightuserdata被认为是一种特殊的userdata,它仅表示一个c的指针,类似数字:你不用创建它,它没有原表,也不需要被gc。Lua如何实现变量可以存储任意类型呢?源码中用一个大的联合体来实现。

代码语言:javascript
复制
/*
** Union of all Lua values
*/
typedef union Value {
  struct GCObject *gc;    /* collectable objects */
  void *p;         /* light userdata */
  lua_CFunction f; /* light C functions */
  lua_Integer i;   /* integer numbers */
  lua_Number n;    /* float numbers */
} Value;


/*
** Tagged Values. This is the basic representation of values in Lua:
** an actual value plus a tag with its type.
*/

#define TValuefields	Value value_; lu_byte tt_

typedef struct TValue {
  TValuefields;
} TValue;

Value中包含各种实际类型需要用到的变量,其中GCobject用于存储需要被gc类型的地址,目前string, userdata, table, function, thread是需要gc的类型,其他几个字段分别用于存储lightuserdata指针,c导出的函数地址,整数,浮点数。TValue包含Value和一个字节的类型信息,是Lua内部存储变量的基础结构。下面我们详细分析一下每种类型的实现。

一,nil

只有一个值nil,与其他类型均不相同。通常用于区分一个值是否是有效值。

二,boolean

类型 boolean 有两个值,false 和 true。 nil 和 false 都使条件为假;它们统称为假值。任何其他值都会使条件为真。boolean在内部实现上,直接给LUA_TBOOLEAN定义了两个扩展类型:LUA_VFALSE和LUA_VTRUE。

代码语言:javascript
复制
/*
** tags for Tagged Values have the following use of bits:
** bits 0-3: actual tag (a LUA_T* constant)
** bits 4-5: variant bits
** bit 6: whether value is collectable
*/

/* add variant bits to a type */
#define makevariant(t,v)	((t) | ((v) << 4))

#define LUA_VFALSE	makevariant(LUA_TBOOLEAN, 0)
#define LUA_VTRUE	makevariant(LUA_TBOOLEAN, 1)

类型的0到3位用于表示基本类型,4到5位被扩展用于表示其他附加信息。

三,number

类型 number 表示整数和实数(浮点数),包含两个子类型:整数和浮点数。标准 Lua 使用 64 位整数和双精度(64 位)浮点数,也可以修改宏定义重新编译 Lua,使其使用 32 位整数和/或单精度(32 位)浮点数。整数和浮点数均为 32 位的选项对于小型机器和嵌入式系统特别有吸引力。 (参见文件 luaconf.h 中的宏 LUA_32BITS。)

代码语言:javascript
复制
/* Variant tags for numbers */
#define LUA_VNUMINT	makevariant(LUA_TNUMBER, 0)  /* integer numbers */
#define LUA_VNUMFLT	makevariant(LUA_TNUMBER, 1)  /* float numbers */

#define ttisnumber(o)		checktype((o), LUA_TNUMBER)
#define ttisfloat(o)		checktag((o), LUA_VNUMFLT)
#define ttisinteger(o)		checktag((o), LUA_VNUMINT)

源码中定义了LUA_TNUMBER两个子类型LUA_VNUMFLT和LUA_VNUMINT分别表示浮点数和整数。实际上内部将整数和浮点数已经按子类型区分开了。

四,string

代码语言:javascript
复制
/*
** Header for a string value.
*/
typedef struct TString {
  CommonHeader;
  lu_byte extra;  /* reserved words for short strings; "has hash" for longs */
  lu_byte shrlen;  /* length for short strings */
  unsigned int hash;
  union {
    size_t lnglen;  /* length for long strings */
    struct TString *hnext;  /* linked list for hash table */
  } u;
  char contents[1];
} TString;

上面是字符串的底层结构,CommonHeader就是支持gc的相关成员。lua中将字符串按长度是否大于LUAI_MAXSHORTLEN(40)分成两种类型LUA_VLNGSTR和LUA_VSHRSTR。extra默认为0,为1表示已经对长字符串hash过,hash字段可以直接使用。如果是短字符串,shrlen表示其长度;如果是长字符串,lnglen表示长字符串的长度。对于短字符串是存放在内部hash表中,hnext指向hash表同一hash桶的下一个短字符串。contents长度为1的数组,用于在字符串末尾添加0,后续分配字符串空间的时候只需要分配TSting和字符串长度即可使用。为了重用短字符串,在global_State中使用hash表strt字段存放。hash表类型stringtable

定义如下:

代码语言:javascript
复制
typedef struct stringtable {
  TString **hash;
  int nuse;  /* number of elements */
  int size;
} stringtable;

其中hash字段就是hash表的桶数组,每个桶是代表这个hash值的TString的链表的头结点。

再回头梳理下字符串的创建过程,可以发现还有一个strcache的过程:

代码语言:javascript
复制
/*
** Create or reuse a zero-terminated string, first checking in the
** cache (using the string address as a key). The cache can contain
** only zero-terminated strings, so it is safe to use 'strcmp' to
** check hits.
*/
TString *luaS_new (lua_State *L, const char *str) {
  unsigned int i = point2uint(str) % STRCACHE_N;  /* hash */
  int j;
  TString **p = G(L)->strcache[i];
  for (j = 0; j < STRCACHE_M; j++) {
    if (strcmp(str, getstr(p[j])) == 0)  /* hit? */
      return p[j];  /* that is it */
  }
  /* normal route */
  for (j = STRCACHE_M - 1; j > 0; j--)
    p[j] = p[j - 1];  /* move out last element */
  /* new element is first in the list */
  p[0] = luaS_newlstr(L, str, strlen(str));
  return p[0];
}

stcache是在globalstate中定义的一个二维数组:TString *strcache[STRCACHE_N][STRCACHE_M];

这个缓存是按照字符串指针地址取模来定位的。无论是长短字符串,如果是经常使用的情况下,会在缓存中快速找到能复用的字符串,提高程序性能。

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=qcbn8o5da0g1

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-08-18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一,nil
  • 二,boolean
  • 三,number
  • 四,string
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档