lua,一款很轻量级很nice很强大的脚本语言,做为lua中使用最为频繁的table表,在使用之时还是有颇多的好处与坑的;

下面是大牛 云风的一片关于lua table的blog,可使得对lua table内在机制 窥测一二;

lua 的整体效率是很高的,其中,它的 table 实现的很巧妙为这个效率贡献很大。

lua 的 table 充当了数组和映射表的双重功能,所以在实现时就考虑了这些,让 table 在做数组使用时尽量少效率惩罚。

lua 是这样做的。它把一个 table 分成数组段和 hash 段两个部分。数字 key 一般放在数组段中,没有初始化过的 key 值全部设置为 nil 。当数字 key 过于离散的时候,部分较大的数字 key 会被移到 hash段中去。这个分割线是以数组段的利用率不低于 50% 为准。 0 和 负数做 key 时是肯定放在 hash 段中的。

string 和 number 都放在一起做 hash ,分别有各自的算法,但是 hash 的结果都在一个数值段中。hash 段采用闭散列方法,即,所有的值都存在于表中。如果hash 发生碰撞,额外的数据记在空闲槽位里,而不额外分配空间存放。当整个个表放满后,hash 段会扩大,所有段内的数据将被重新 hash ,重新 hash 后,冲突将大大减少。

这种 table 的实现策略,首先保证的是查找效率。对于把 table 当数组使用时将和 C 数组一样高效。对于 hash 段的值,查找几乎就是计算 hash 值的过程(其中string 的 hash 值是事先计算好保存的),只有在碰撞的时候才会有少许的额外查找时间,而空间也不至于过于浪费。在 hash 表比较满时,插入较容易发生碰撞,这个时候,则需要在表中找到空的插槽。lua 在table 的结构中记录了一个指针顺次从一头向另一头循序插入来解决空槽的检索。每个槽点在记录 next 指针保存被碰撞的 key 的关联性。

整个来说,这种解决方法是非常不错的。

关于映射表的实现,我前段时间也做过一个别的研究。贴在留言本上:
<a href="http://www.codingnow.com/2004/board/view.php?paster=777&reply=0">树表结合的一种映射表实现</a>
<a href="http://www.codingnow.com/2004/board/view.php?paster=776&reply=0">在 vector , map , list 间取得平衡</a>

原文链接: http://blog.codingnow.com/2005/10/lua_table.html

即便作为lua 开发蛮久的coder来讲,很多东西不亲自去考究一下,还不是很清晰的,不如lua table的长度问题就是一个 很奇葩的例子;下面的这些也许你就不是很清楚了;

想要取得lua table长度,有这么几种方法,table.getn(table_name), #table_name, table.maxn(table_name), 再加上 ipairs(table_name) 和pairs(table_name)遍历;

根据云风所写的文章可以得知,lua的两种不同的存储方式,自然的,上述的几种 取得lua table 长度的几种方式也 存在区别;

table.maxn(table)

table.maxn()函数返回指定table中所有正数key值中最大的key值. 如果不存在key值为正数的元素, 则返回0. 此函数不限于table的数组部分.

table.getn(table)
返回table中元素的个数

#(table)

返回的是lua table 中key为连续整型数字(抑或是 默认整型)的长度数;

pairs()函数基本和ipairs()函数用法相同, 区别在于pairs()可以遍历整个table, 即包括数组及非数组部分.

关于对lua table长度的问题,http://blog.csdn.net/dssdss123/article/details/12676329 对于一些奇葩问题的讲述还是有些深入的;亲测【lua version=5.1.4】,的确如此;

但是还是有些东西需要补充的,对于 #用法,其表现和table.getn()在很多极端的情况下都是类似的;table.maxn(),因为获取的是table中所有正数key值中最大的key值.可以不连续;

local tblTest =
{
"this 1",
"this 2",
[] = ,
[] = ,
[] = ,
"this 3",
[] = ,
}
print(table.getn(tblTest))
print(#(tblTest))
print(table.maxn(tblTest)) --===========================
>lua -e "io.stdout:setvbuf 'no'" "filedeal.lua" --=========================== local tblTest =
{
"this 1",
[] = ,
[] = ,
[] = ,
"this ",
--"adsfasd",
[] = ,
}
print(table.getn(tblTest))
print(#(tblTest))
print(table.maxn(tblTest))
--===========================
>lua -e "io.stdout:setvbuf 'no'" "filedeal.lua" --=========================== local tblTest =
{
"this 1",
[] = ,
[] = ,
[] = ,
--"adsfasd",
[] = ,
}
print(table.getn(tblTest))
print(#(tblTest))
print(table.maxn(tblTest))
--===========================
>lua -e "io.stdout:setvbuf 'no'" "filedeal.lua" --===========================

上述三个tabTest 的不同在于 这都是lua默认的下表是从1开始,有两个的默认的,使得 [3]=2,这项元素足以将连续性接上,当接不上的时候,因为不连续行,自然打印值有所不同了;

倘若在后面或者该表 其中再坠入一个nil,所输出来的内容又是不一样的:所以~不要在lua的table中使用nil值,如果一个元素要删除,直接remove,不要用nil去代替。

倘若再将元素后面加一项 下表默认的元素,其结果会怎样呢? 例 如下代码:

local tblTest =
{
"this 1",
[] = ,
[] = ,
[] = ,
"this 3",
--"adsfasd",
[] = ,
}
for k , v in ipairs(tblTest) do
print(k,v)
end
--=============================
this
this --============================= local tblTest =
{
"this 1",
[] = ,
[] = ,
[] = ,
"this 3",
"this 4",
--"adsfasd",
[] = ,
}
for k , v in ipairs(tblTest) do
print(k,v)
end --=============================
this
this
this --=============================

由此可见,lua 默认的下表值会将显示的覆盖,即便是 再调整下顺序 也是如是,至于为何如此,不理解,有待参悟【欢求 大神指正】;

这样的意外在lua中 挺多的,只要明白了 基本的原理,倒也不足为奇了;

至于lua table的遍历 可参见 http://rangercyh.blog.51cto.com/1444712/1032925 这这篇文章;讲的挺详细的;

另外: 关于lua table的其他小问题:

1, 配置lua table 元素之间,以”,“ 或者”;“完全是一样的【可参见lua手册】,看你的爱好了,推荐的是:用分好可以作为 元素类型的不同而分割开显示下;

2,不要在lua的table中使用nil值,如果一个元素要删除,直接remove,不要用nil去代替。

3,判断lua table 是否为nil 不能用 if a == {} then 【错误的】(这样的结果就是a == {}永远返回false,是一个逻辑错误。因为这里比较的是table a和一个匿名table的内存地址。);

   if table.maxn(a) == 0 then 【错误的】这样做不保险啊,除非table的key都是数字,而没有hash部分。

  if #(a)  == 0 then 也是不靠谱的,除非你能保证没人这样写这个table like this:tab = {nil,1,nil;} 用#tab print出来 的确是0, 能说此tab是nil的?

   可以使用lua内置的next来判断; if next(a) == 0 then ;

4,应该尽量使用 local 变量而非 global 变量。这是 Lua 初学者最容易犯的错误。 global 变量实际上是放在一张全局的 table 里的。 global 变量实际上是利用一个 string (变量名作 key) 去访问这个 table 。 虽然[InterWiki]Lua5 的 table 效率很高 ,但是相对于 local 变量,依然有很大的效率损失。 local 变量是直接通过 Lua 的堆栈访问的。有些 global 变量的访问是不经意的,比如双重for中使用的pairs或者ipirs(全局函数),如果在使用循环外层 local pairs=pairs会对性能有些不同层次的提升;

5, 警惕临时变量 字符串的连接操作,会产生新的对象。这是由 lua 本身的 string 管理机制导致的。lua 在 VM 内对相同的 string 永远只保留一份唯一 copy ,这样,所有字符串比较就可以简化为地址比较。这也是 lua 的 table 工作很快的原因之一。这种 string 管理的策略,跟 java 等一样,所以跟 java 一样,应该尽量避免在循环内不断的连接字符串,比如 a = a..x 这样。每次运行,都很可能会生成一份新的 copy 。

6, 同样,记住,每次构造一份 table 都会多一份 table 的 copy 。比如在 lua 里,把平面坐标封装成 { x, y } 用于参数传递,就需要考虑这个问题。每次你想构造一个坐标对象传递给一个函数,{ 10,20 } 这样明确的写出,都会构造一个新的 table 出来。要么,我们想办法考虑 table 的重用;要么,干脆用 x,y 两个参数传递坐标。 同样需要注意的是以 function foo (...) 这种方式定义函数, ... 这种不定参数,每次调用的时候都会被定义出一个 table 存放不定数量的参数。 这些临时构造的对象往往要到 gc 的时候才被回收,过于频繁的 gc 有时候正是效率瓶颈。

7,【未完待续...】

lua的table表处理 及注意事项的更多相关文章

  1. Lua 数组排序 table.sort的注意事项

    1. table中不能有nil table.sort是排序函数,它要求要排序的目标table的必须是从1到n连续的,即中间不能有nil. 2. 重写的比较函数,两个值相等时不能return true ...

  2. 打印Lua的Table对象

    小伙伴们再也不用为打印lua的Table对象而苦恼了, 本人曾也苦恼过,哈哈 不过今天刚完成了这个东西, 以前在网上搜过打印table的脚本,但是都感觉很不理想,于是,自己造轮子了~ 打印的效果,自己 ...

  3. lua weak table 概念解析

    lua weak table 经常看到lua表中有 weak table的用法, 例如: weak_table = setmetatable({}, {__mode="v"}) 官 ...

  4. lua中 table 元表中元方法的重构实现

    转载请标明出处http://www.cnblogs.com/zblade/ lua作为游戏的热更新首选的脚本,其优势不再过多的赘述.今天,我主要写一下如何重写lua中的元方法,通过自己的重写来实现对l ...

  5. Linux下C/C++和lua交互-Table

    本来这些文章都是在我的个人网站www.zhangyi.studio,目前处在备案状态,暂时访问不了,所以搬到这边.  最近这两天需要弄清楚C++和lua间相互调用和数据传递,废话不多说,直接上过程. ...

  6. lua中 table 重构index/pairs元方法优化table内存占用

    转载请标明出处http://www.cnblogs.com/zblade/ lua作为游戏的热更新首选的脚本,其优势不再过多的赘述.今天,我主要写一下如何重写lua中的元方法,通过自己的重写来实现对l ...

  7. lua中table的遍历,以及删除

    Lua 内table遍历 在lua中有4种方式遍历一个table,当然,从本质上来说其实都一样,只是形式不同,这四种方式分别是: 1. ipairs for index, value in ipair ...

  8. C调用lua的table里面的函数

    网上搜索C.C++调用lua函数,有一大堆复制粘贴的. 但是搜索<C调用lua的table里面的函数> 怎么就没几个呢? 经过探索,发现其实逻辑是这样的: 1.根据name获取table ...

  9. lua 的 table 处理

    lua 的整体效率是很高的,其中,它的 table 实现的很巧妙为这个效率贡献很大. lua 的 table 充当了数组和映射表的双重功能,所以在实现时就考虑了这些,让 table 在做数组使用时尽量 ...

随机推荐

  1. 动态加载js文件

    由于最近在弄echarts,关于地图类的效果,但是全国地图整体的js文件太大了,加载很耗费资源,所以要根据不同省份加载不同地区的js地图, 于是就想的比较简单, var script = docume ...

  2. How to copy remote computer files quickly to local computer

    if we want copy file from VM(Remote VM) to local computer. Always can not easy copy file so easy. no ...

  3. Redis第二篇(Redis基本命令)

    -x     从标准输入读取一个参数 such as: echo –en “shaw” |./redis-cli –x setname == set name shaw -r     重复执行一个命令 ...

  4. 算法入门笔记------------Day4

    1.WERTYU 输入一个错位后敲出的字符串,输出打字员本来想打出的字 #include<stdio.h> char *s="`1234567890-=QWERTYUIOP[]\ ...

  5. 基于VC的声音文件操作(五)

    (六)读取波形文件的实例 1.打开文件后,可通过HMMO句柄获得文件中的波形部份:MMCKINFO mmckinfo;mmckinfo.fccType = mmioFOURCC('W','A','V' ...

  6. react-router+webpack+gulp路由实例

    背景:新项目要开始了,有一种想要在新项目中使用react的冲动,应该也是一个单页面的应用,单页应用就涉及到一个路由的问题.于是最近在网上找了蛮多关于react-router的文章,也遇到了许多的坑,经 ...

  7. javascriptone

    var start=Date.now();document.write("<h1>This is a paragraph.</h1>");function ...

  8. NYOJ 536 开心的mdd(DP)

    开心的mdd 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 himdd有一天闲着无聊,随手拿了一本书,随手翻到一页,上面描述了一个神奇的问题,貌似是一个和矩阵有关的 ...

  9. 基于java代码的Spring-mvc框架配置

     Spring 版本 4.3.2   maven项目 1.首先上项目目录图,主要用到的配置文件,略去css和js的文件 引包: 2.主要代码: (1)NetpageWebAppInitializer类 ...

  10. C++混合编程之idlcpp教程Lua篇(7)

    上一篇在这 C++混合编程之idlcpp教程Lua篇(6) 第一篇在这 C++混合编程之idlcpp教程(一) 与LuaTutorial4工程相似,工程LuaTutorial5中,同样加入了四个文件: ...