Lua基础之table详解

 

Lua基础之table详解

标签: luatable
  4651人阅读  评论(0)  收藏  举报
  分类:

概要:1.table特性;2.table的构造;3.table常用函数;4.table遍历;5.table面向对象

 原文地址:http://blog.csdn.net/dingkun520wy/article/details/50231603

1.table特性

table是一个“关联数组”,数组的索引可以是数字或者是字符串,所有索引值都需要用 "[""]" 括起来;如果是字符串,还可以去掉引号和中括号; 即如果没有[]括起,则认为是字符串索引

table 的默认初始索引一般以 1 开始,如果不写索引,则索引就会被认为是数字,并按顺序自动从1往后编;

table 的变量只是一个地址引用,对 table 的操作不会产生数据影响

table 不会固定长度大小,有新数据插入时长度会自动增长

table 里保存数据可以是任何类型,包括function和table

table所有元素之间,总是用逗号 "" 隔开;


2.table的构造

创建table

[plain]  view plain  copy
  1. t = {}          --定义一个空表  
  2. t["jun"] = 6    --字符串key值的属性  
  3. t[1] = 1        --数字key值的属性  
  4. t.jun = 16      --字符串key值的简写  
  5. t.test = {num=28,str="test"}    --属性可以是table  
  6. print(t.test.num)               --输出28  
  7. t.testFunction = function() print("函数") end  --属性可以是function  
  8. t.testFunction()                --调用函数  
  9. t:testFunction()                --同上  
  10.   
  11. --上面的table还可以这么写  
  12. t=  
  13. {  
  14.     1,  
  15.     jun = 6,  
  16.     test=  
  17.     {  
  18.         num = 28,  
  19.         str = "test",  
  20.     }  
  21.     testFunction = function() print("函数") end,  
  22. }  


3.table常用函数

table.pack(...)

获取一个索引从 1 开始的参数表 table,并会对这个 table 预定义一个字段 n,表示该表的长度

[plain]  view plain  copy
  1. function table_pack(param, ...)  
  2.     local arg = table.pack(...)  
  3.     print("this arg table length is", arg.n)  
  4.     for i = 1, arg.n do  
  5.         print(i, arg[i])  
  6.     end  
  7. end  
  8.    
  9. table_pack("test", "param1", "param2", "param3")  

table.concat(table, sep,  start, end)

table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开。除了table外, 其他的参数都不是必须的, 分隔符的默认值是空字符, start的默认值是1, end的默认值是数组部分的总长.

sep, start, end这三个参数是顺序读入的, 所以虽然它们都不是必须参数, 但如果要指定靠后的参数, 必须同时指定前面的参数.

lua 中字符串的存储方式与 C 不一样,lua 中的每个字符串都是单独的一个拷贝,拼接两个字符串会产生一个新的拷贝,如果拼接操作特别多,就会影响性能,所以对于密集型的字符并接,table.concat 比用 ".." 连接更高效。

[plain]  view plain  copy
  1. local tbl = {"apple", "pear", "orange", "grape"}  
  2.    
  3. print(table.concat(tbl))  
  4.    
  5. print(table.concat(tbl, "、"))  
  6.    
  7. print(table.concat(tbl, "、", 2))  
  8.    
  9. print(table.concat(tbl, "、", 2, 3))  

table.unpack(table, start, end)

用于返回 table 里的元素,参数 start 是开始返回的元素位置,默认是 1,参数 end 是返回最后一个元素的位置,默认是 table 最后一个元素的位置,参数 start、end 都是可选

[plain]  view plain  copy
  1. local tbl = {"apple", "pear", "orange", "grape"}  
  2. print(table.unpack(tbl))  
  3.    
  4. local a, b, c, d = table.unpack(tbl)  
  5. print(a, b, c, d)  
  6.    
  7. print(table.unpack(tbl, 2))  
  8. print(table.unpack(tbl, 2, 3))  
table.maxn(table)

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

[plain]  view plain  copy
  1. tbl = {[1] = "a", [2] = "b", [3] = "c", [26] = "z"}  
  2. print(#tbl)           --3因为26和之前的数字不连续, 所以不算在数组部分内  
  3. print(table.maxn(tbl))   --26  
  4. tbl[91.32] = true  
  5. print(table.maxn(tbl))  --91.32  


table.getn(table)

返回table中元素的个数

[plain]  view plain  copy
  1. t1 = {1, 2, 3, 5};  
  2. print(getn(t1))  
  3. --4  


table.insert(table, pos, value)

用于向 table 的指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾.

[plain]  view plain  copy
  1. local tbl = {"apple", "pear", "orange", "grape"}  
  2.    
  3. table.insert(tbl, "watermelon")  
  4. print(table.concat(tbl, "、"))  
  5.    
  6. table.insert(tbl, 2, "watermelon")  
  7. print(table.concat(tbl, "、"))  

table.remove(table, pos)

删除并返回table数组部分位于pos位置的元素. 其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元素删起,并且参数 pos 的类型只能是数字 number 类型。

[plain]  view plain  copy
  1. local tbl = {"apple", "pear", "orange", "grape"}  
  2. table.remove(tbl, 2)  
  3. print(table.concat(tbl, "、"))  
  4.    
  5. table.remove(tbl)  
  6. print(table.concat(tbl, "、"))  

table.sort(table, comp)

用于对 table 里的元素作排序操作,参数 comp 是一个排序对比函数,它有两个参数 param1、param2,如果 param1 排在 param2 前面,那么排序函数返回 true,否则返回 false。参数 comp 可选,缺省 comp 的情况下是对表作升序排序。

[plain]  view plain  copy
  1. local tbl = {"apple", "pear", "orange", "grape"}  
  2. local sort_func1 = function(a, b) return a > b end  
  3. table.sort(tbl, sort_func1)  
  4. print(table.concat(tbl, "、"))  
  5.    
  6. local sort_func2 = function(a, b) return a < b end  
  7. table.sort(tbl, sort_func2)  
  8. print(table.concat(tbl, "、"))  
  9. local tbl = {"apple", "pear", "orange", "grape"}  
  10. table.sort(tbl)  
  11. print(table.concat(tbl, "、"))  


table.foreachi(table, function(i, v))

会期望一个从 1(数字 1)开始的连续整数范围,遍历table中的key和value逐对进行function(i, v)操作

[plain]  view plain  copy
  1. t1 = {2, 4, 6, language="Lua", version="5", 8, 10, 12, web="hello lua"};  
  2. table.foreachi(t1, function(i, v) print (i, v) end) ;   
  3. --结果1 2  
  4. --2 4  
  5. --3 6  
  6. --4 8  
  7. --5 10  
  8. --6 12  

table.foreach(table, function(i, v))

与foreachi不同的是,foreach会对整个表进行迭代

[plain]  view plain  copy
  1. t1 = {2, 4, 6, language="Lua", version="5", 8, 10, 12, web="hello lua"};  
  2. table.foreach(t1, function(i, v) print (i, v) end) ;  
  3. --[[  
  4. 输出结果:  
  5. 1 2  
  6. 2 4  
  7. 3 6  
  8. 4 8  
  9. 5 10  
  10. 6 12  
  11. web hello lua  
  12. language Lua  
  13. version 5  
  14. ]]  


4.table遍历

for key, value in pairs(tbtest) do      
     print(value)
end  

这样的遍历顺序并非是tbtest中table的排列顺序,而是根据tbtest中key的hash值排列的顺序来遍历的。 for key, value in ipairs(tbtest) do
     print(value)
end  
这样的循环必须要求tbtest中的key为顺序的,而且必须是从1开始,ipairs只会从1开始按连续的key顺序遍历到key不连续为止。

5.table面向对象

和编译型的面向对象语言不同,在lua中不存在类的定义这样一个概念,不管是类的定义还是类的实例都需要通过lua table来模拟。

[plain]  view plain  copy
  1. Test = {jun = 0}  
  2. function Test.withdraw(self,v)  
  3.      self.jun = self.jun - v  
  4.  end  
  5.  --下面是代码的调用:  
  6. a = Test  
  7. a.withdraw(a,10)  
Lua提供了一种更为便利的语法,即将点 (.) 替换为冒号 (:) ,这样可以在定义和调用时均隐藏self参数
[plain]  view plain  copy
  1. function Test:withdraw(v)  
  2.      self.jun = self.jun - v  
  3.  end  
  4. a = Test  
  5. a:withdraw(10)  

Lua 没有类的概念,不过可以通过元表(metatable)来实现与原型 prototype 类似的功能,而 prototype 与类的工作机制一样,都是定义了特定对象行为。Lua 里的原型特性主要使用元表的 __index 事件来实现,这样当调用对象没定义的方法时,会向其元表的 __index 键(事件)查找。例如有 a 和 b 两个对象,想让 b 作为 a 的原型 prototype,只需要把 b 设置为 a 元表的 __index 值就行:当对象 a 调用任何不存在的成员都会到对象 b 中查找,a 可以拥有或调用 b 的属性或方法,从某种意义上看,b 可以看作是一个类,a 是 b 的对象。

[plain]  view plain  copy
  1. --[[  
  2. 在这段代码中,我们可以将Account视为class的声明,如Java中的:  
  3. public class Account   
  4. {  
  5.     public float balance = 0;  
  6.     public Account(Account o);  
  7.     public void deposite(float f);  
  8. }  
  9. --]]  
  10. --这里balance是一个公有的成员变量。  
  11. Account = {balance = 0}  
  12.   
  13. --new可以视为构造函数  
  14. function Account:new(o)  
  15.     o = o or {} --如果参数中没有提供table,则创建一个空的。  
  16.     --将新对象实例的metatable指向Account表(类),这样就可以将其视为模板了。  
  17.     setmetatable(o,self)  
  18.     --在将Account的__index字段指向自己,以便新对象在访问Account的函数和字段时,可被直接重定向。  
  19.     self.__index = self  
  20.     --最后返回构造后的对象实例  
  21.     return o  
  22. end  
  23.   
  24. --deposite被视为Account类的公有成员函数  
  25. function Account:deposit(v)  
  26.     --这里的self表示对象实例本身  
  27.     self.balance = self.balance + v  
  28. end  
  29.   
  30. --下面的代码创建两个Account的对象实例  
  31.   
  32. --通过Account的new方法构造基于该类的示例对象。  
  33. a = Account:new()  
  34. --[[  
  35. 这里需要具体解释一下,此时由于table a中并没有deposite字段,因此需要重定向到Account,  
  36. 同时调用Account的deposite方法。在Account.deposite方法中,由于self(a对象)并没有balance  
  37. 字段,因此在执行self.balance + v时,也需要重定向访问Account中的balance字段,其缺省值为0。  
  38. 在得到计算结果后,再将该结果直接赋值给a.balance。此后a对象就拥有了自己的balance字段和值。  
  39. 下次再调用该方法,balance字段的值将完全来自于a对象,而无需在重定向到Account了。  
  40. --]]  
  41. a:deposit(100.00)  
  42. print(a.balance) --输出100  
  43.   
  44. b = Account:new()  
  45. b:deposit(200.00)  
  46. print(b.balance) --输出200  


继承

[plain]  view plain  copy
  1. --需要说明的是,这段代码仅提供和继承相关的注释,和类相关的注释在上面的代码中已经给出。  
  2. Account = {balance = 0}  
  3.   
  4. function Account:new(o)  
  5.     o = o or {}  
  6.     setmetatable(o,self)  
  7.     self.__index = self  
  8.     return o  
  9. end  
  10.   
  11. function Account:deposit(v)  
  12.     self.balance = self.balance + v  
  13. end  
  14.   
  15. function Account:withdraw(v)  
  16.     if v > self.balance then  
  17.         error("Insufficient funds")  
  18.     end  
  19.     self.balance = self.balance - v  
  20. end  
  21.   
  22. --下面将派生出一个Account的子类,以使客户可以实现透支的功能。  
  23. SpecialAccount = Account:new()  --此时SpecialAccount仍然为Account的一个对象实例  
  24.   
  25. --派生类SpecialAccount扩展出的方法。  
  26. --下面这些SpecialAccount中的方法代码(getLimit/withdraw),一定要位于SpecialAccount被Account构造之后。  
  27. function SpecialAccount:getLimit()  
  28.     --此时的self将为对象实例。  
  29.     return self.limit or 0  
  30. end  
  31.   
  32. --SpecialAccount将为Account的子类,下面的方法withdraw可以视为SpecialAccount  
  33. --重写的Account中的withdraw方法,以实现自定义的功能。  
  34. function SpecialAccount:withdraw(v)  
  35.     --此时的self将为对象实例。  
  36.     if v - self.balance >= self:getLimit() then  
  37.         error("Insufficient funds")  
  38.     end  
  39.     self.balance = self.balance - v  
  40. end  
  41.   
  42. --在执行下面的new方法时,table s的元表已经是SpecialAccount了,而不再是Account。  
  43. s = SpecialAccount:new{limit = 1000.00}  
  44. --在调用下面的deposit方法时,由于table s和SpecialAccount均未提供该方法,因此访问的仍然是  
  45. --Account的deposit方法。  
  46. s:deposit(100)  
  47.   
  48.   
  49. --此时的withdraw方法将不再是Account中的withdraw方法,而是SpecialAccount中的该方法。  
  50. --这是因为Lua先在SpecialAccount(即s的元表)中找到了该方法。  
  51. s:withdraw(200.00)  
  52. print(s.balance) --输出-100  

私密性

私密性对于面向对象语言来说是不可或缺的,否则将直接破坏对象的封装性。Lua作为一种面向过程的脚本语言,更是没有提供这样的功能,然而和模拟支持类与继承一样,我们仍然可以在Lua中通过特殊的编程技巧来实现它,这里我们应用的是Lua中的闭包函数。

[plain]  view plain  copy
  1. --这里我们需要一个闭包函数作为类的创建工厂  
  2. function newAccount(initialBalance)  
  3.     --这里的self仅仅是一个普通的局部变量,其含义完全不同于前面示例中的self。  
  4.     --这里之所以使用self作为局部变量名,也是为了方便今后的移植。比如,以后  
  5.     --如果改为上面的实现方式,这里应用了self就可以降低修改的工作量了。  
  6.     local self = {balance = initialBalance} --这里我们可以将self视为私有成员变量  
  7.     local withdraw = function(v) self.balance = self.balance - v end  
  8.     local deposit = function(v) self.balance = self.balance + v end  
  9.     local getBalance = function() return self.balance end  
  10.     --返回对象中包含的字段仅仅为公有方法。事实上,我们通过该种方式,不仅可以实现  
  11.     --成员变量的私有性,也可以实现方法的私有性,如:  
  12.     --local privateFunction = function() --do something end  
  13.     --只要我们不在输出对象中包含该方法的字段即可。  
  14.     return {withdraw = withdraw, deposit = deposit, getBalance = getBalance}  
  15. end  
  16.   
  17. --和前面两个示例不同的是,在调用对象方法时,不再需要self变量,因此我们可以直接使用点(.),  
  18. --而不再需要使用冒号(:)操作符了。  
  19. accl = newAccount(100.00)  
  20. --在函数newAccount返回之后,该函数内的“非局部变量”表self就不再能被外部访问了,只能通过  
  21. --该函数返回的对象的方法来操作它们。  
  22. accl.withdraw(40.00)  
  23. print(acc1.getBalance())  
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值