Lua学习笔记:浅谈table的实现

这篇具有很好参考价值的文章主要介绍了Lua学习笔记:浅谈table的实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言
本篇在讲什么

Lua中的table的实现
本篇适合什么

适合初学Lua的小白
本篇需要什么

Lua语法有简单认知
依赖Sublime Text编辑器

本篇的特色

具有全流程的图文教学
重实践,轻理论,快速上手
提供全流程的源码内容

Lua学习笔记:浅谈table的实现,lua学习笔记,lua,学习,笔记
★提高阅读体验★

👉 ♠ 一级标题 👈

👉 ♥ 二级标题 👈

👉 ♣ 三级标题 👈

👉 ♦ 四级标题 👈


♠ table的定义

摘自Lua5.1源码文件lobject.h

/*
** Tables
*/

typedef union TKey {
  struct {
    TValuefields;
    struct Node *next;  /* for chaining */
  } nk;
  TValue tvk;
} TKey;


typedef struct Node {
  TValue i_val;
  TKey i_key;
} Node;


typedef struct Table {
  CommonHeader;
  lu_byte flags;  /* 1<<p means tagmethod(p) is not present */ 
  lu_byte lsizenode;  /* log2 of size of `node' array */
  struct Table *metatable;
  TValue *array;  /* array part */
  Node *node;
  Node *lastfree;  /* any free position is before this position */
  GCObject *gclist;
  int sizearray;  /* size of `array' array */
} Table;

  • flags:元方法的标记,用于查询table是否包含某个类别的元方法
  • lsizenode:表示table的hash部分大小,2的幂数
  • metatable:该表的元表
  • array:table的数组部分
  • node:hash表的起始位置指针
  • lastfree:hash表最后位置的指针
  • gclist:gc相关链表
  • sizearray:数组的大小,不一定是2的幂数

每个table,最多会由三块连续内存构成

  • 一个 table 结构
  • 一块存放了连续整数索引的数组
  • 和一块大小为 2 的整数次幂的哈希表

♠ table的创建

在之前C/C++操作Lua的表中就了解过,创建Lua的表可以通过通过函数lua_createtable,源码如下所示

LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
  lua_lock(L);
  luaC_checkGC(L);
  sethvalue(L, L->top, luaH_new(L, narray, nrec));
  api_incr_top(L);
  lua_unlock(L);
}

Lua学习笔记:浅谈table的实现,lua学习笔记,lua,学习,笔记

其中创建函数调用的事luaH_new函数,其定义在ltabel.c脚本内

Table *luaH_new (lua_State *L, int narray, int nhash) {
  Table *t = luaM_new(L, Table);
  luaC_link(L, obj2gco(t), LUA_TTABLE);
  t->metatable = NULL;
  t->flags = cast_byte(~0);
  /* temporary values (kept only if some malloc fails) */
  t->array = NULL;
  t->sizearray = 0;
  t->lsizenode = 0;
  t->node = cast(Node *, dummynode);
  setarrayvector(L, t, narray);
  setnodevector(L, t, nhash);
  return t;
}

可根据传入的narray和nhash,初始化数组和hash表的大小


♠ table的销毁

void luaH_free (lua_State *L, Table *t) {
  if (t->node != dummynode)
    luaM_freearray(L, t->node, sizenode(t), Node);
  luaM_freearray(L, t->array, t->sizearray, TValue);
  luaM_free(L, t);
}
  • 释放数组
  • 释放hash表
  • 释放table结构

♠ table的操作

针对table有多种这里我们挑一些看看源码,了解一下大致原理


♥ 读

源码摘自ltable.c,主要的查询入口是luaH_get函数

/*
** main search function
*/
const TValue *luaH_get (Table *t, const TValue *key) {
  switch (ttype(key)) {
    case LUA_TNIL: return luaO_nilobject;
    case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
    case LUA_TNUMBER: {
      int k;
      lua_Number n = nvalue(key);
      lua_number2int(k, n);
      if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
        return luaH_getnum(t, k);  /* use specialized version */
      /* else go through */
    }
    default: {
      Node *n = mainposition(t, key);
      do {  /* check whether `key' is somewhere in the chain */
        if (luaO_rawequalObj(key2tval(n), key))
          return gval(n);  /* that's it */
        else n = gnext(n);
      } while (n);
      return luaO_nilobject;
    }
  }
}

会根据传入的key的类型,去调用对应类型的查询方法
如果key的类型是nil,则直接返回nil,table的key不能为nil
整数会根据大小,如果不超过数组长度,优先从数组内去查询
超过数组长度的key或者其他类型的key,直接从hash表内查询对应的值


♠ 写

同样的在之前操作表的学习中我们知道了可以通过以下几个函数来修改或添加表的键值

  • lua_settable
  • lua_setfield
  • lua_rawset
  • lua_rawseti

查看源码,这几个接口最终都是调用了函数luaH_set,代码如下所示

TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
  const TValue *p = luaH_get(t, key);
  t->flags = 0;
  if (p != luaO_nilobject)
    return cast(TValue *, p);
  else {
    if (ttisnil(key)) luaG_runerror(L, "table index is nil");
    else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
      luaG_runerror(L, "table index is NaN");
    return newkey(L, t, key);
  }
}

♠ 获取长度

获取table的长度通过函数luaH_getn,源码如下,这里需要注意,如果表不是从1开始的连续整数为key,长度获取可能会错乱

/*
** Try to find a boundary in table `t'. A `boundary' is an integer index
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
*/
int luaH_getn (Table *t) {
  unsigned int j = t->sizearray;
  if (j > 0 && ttisnil(&t->array[j - 1])) {
    /* there is a boundary in the array part: (binary) search for it */
    unsigned int i = 0;
    while (j - i > 1) {
      unsigned int m = (i+j)/2;
      if (ttisnil(&t->array[m - 1])) j = m;
      else i = m;
    }
    return i;
  }
  /* else must find a boundary in hash part */
  else if (t->node == dummynode)  /* hash part is empty? */
    return j;  /* that is easy... */
  else return unbound_search(t, j);
}

♠ 总结一下

table的实现就是通过一个固定长度的数组和一个hash表构成的


♠ 推送

  • Github
https://github.com/KingSun5

♠ 结语

若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。文章来源地址https://www.toymoban.com/news/detail-526952.html

👉 本文属于原创文章,转载请评论留言,并在转载文章头部著名作者出处👈

到了这里,关于Lua学习笔记:浅谈table的实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Lua学习笔记之迭代器、table、模块和包、元表和协程

    迭代器是一种对象,它能够来遍历标准库模板容器中的部分或全部元素,每个迭代器对象代表容器中确定的地址,在Lua中迭代器是一种支持指针类型的结构,他可以遍历集合的每一个元素。 泛型for自己内部保存迭代函数,实际上保存三个值:迭代函数、状态常量、控制变量。

    2024年03月09日
    浏览(61)
  • Lua学习笔记:面向对象的实现

    前言 本篇在讲什么 Lua中的面向对象的实现 本篇适合什么 适合 初学Lua 的小白 本篇需要什么 对 Lua 语法有简单认知 依赖 Sublime Text 编辑器 本篇的特色 具有全流程的 图文教学 重实践,轻理论,快速上手 提供全流程的 源码 内容 ★提高阅读体验★ 👉 ♣ 三级标题 👈 👉 ♦

    2024年02月13日
    浏览(47)
  • 【Lua学习笔记】Lua入门

    (不是教程,推荐有编程基础的人观看本文) 文中主要包含了对菜鸟教程中的一些学习理解,个人感觉Lua语言和Python很多地方相似 以下大部分代码和表格摘抄自菜鸟教程 数据类型 描述 nil 只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)(类似与Null或者

    2024年02月15日
    浏览(36)
  • 【Lua学习笔记】Lua进阶——协程

    协程是一种并发操作,相比于线程,线程在执行时往往是并行的,并且线程在创建销毁执行时极其消耗资源,并且过长的执行时间会造成主进程阻塞。而协程可以以并发时轮值时间片来执行,优点是不会阻塞,消耗资源少,可以手动控制。至于协程和线程的区别,什么是并发

    2024年02月15日
    浏览(94)
  • 【Lua学习笔记】Lua进阶——函数和闭包

    使用函数嵌套的用法,我们可以将另一个函数作为返回值,但是返回函数作为一个值是要被赋值给其他变量的,所以return时不能起名(赋值)为其他变量名。 推荐阅读深入Lua:函数和闭包 在函数嵌套中,我们需要接触一个叫做闭包的概念 这就是一个闭包,它由一个函数和该

    2024年02月15日
    浏览(56)
  • 【Lua学习笔记】Lua进阶——Require,三目运算

    这是文件 aaa.lua 的内容 这是文件 example.lua 的内容 可以看到,在使用require之后,会直接对其他文件进行调用执行。而且我们可以直接访问它的全局变量,并且发现我们的全局变量被覆盖了,而它的局部变量就像private一样,不能被这个文件访问。 从 package.loaded 这个方法我们可

    2024年02月15日
    浏览(50)
  • lua学习笔记21完结篇(lua中的垃圾回收)

    输出 学习地址  【唐老狮】Unity热更新之Lua语法_哔哩哔哩_bilibili 

    2024年04月15日
    浏览(45)
  • Lua学习笔记:require非.lua拓展名的文件

    前言 本篇在讲什么 Lua的require相关的内容 本篇需要什么 对 Lua 语法有简单认知 对 C++ 语法有简单认知 依赖 Visual Studio 工具 本篇的特色 具有全流程的 图文教学 重实践,轻理论,快速上手 提供全流程的 源码 内容 ★提高阅读体验★ 👉 ♣ 三级标题 👈 👉 ♦ 四级标题 👈 想

    2024年02月07日
    浏览(41)
  • lua学习笔记

    单行注释: 多行注释: 命名: Lua不支持下划线+大写字母,比如:_ABC 但支持:_abc : 全局变量: 直接变量名 = 内容就是全局 局部变量: 加上local即可 nil: nil是空的意思,即什么也没有 lua的数据类型: table: lua从下表为1开始的 if else elseif: nil默认为false ..: ..为字

    2024年02月07日
    浏览(41)
  • lua脚本语言学习笔记

    Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。 因为我们使用redis的时候一般要写lua脚本,这篇文章就介绍一下lua脚本语言的基础用法。 window操作系统下可以使用SciTE来

    2024年02月16日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包