Lua笔记
只是为了防止忘记而写的记录。
1.表的构造,所有的索引值都必须用[ ]表示,如果是字符串,可以去掉引号和中括号
2. a and b 如果a为 false,返回a,否则b
a or b 如果a为真,返回a,否则b
3.
1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 --倒置的链表 3 list = nil 4 for i = 1, 10 do 5 list = { next = list, value = i} 6 end 7 8 local l = list 9 while l do 10 print(l.value) 11 l = l.next 12 end 13 14 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 --队列 16 List = {} 17 function List.new() 18 return {fisrt = 0, last = 0} 19 end 20 function List.push(Q,value) 21 local last = Q.last + 1 22 Q[last] = value 23 Q.last = last 24 end 25 26 function List.pop(Q) 27 local first = Q.first + 1 28 29 if first > Q.last then return error("error") end 30 Q.first = first 31 return Q[first-1] 32 end 33 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 34 串行化: 35 function serialize(o) 36 if type(o) == "number" then 37 io.write(o) 38 elseif type(o) == "string" then 39 --string.format函数的"%q"参数可以转义字符串中的元字符。 40 io.write(string.format("%q",o)) 41 elseif type(o) == "table" then 42 io.write("{\n") 43 --迭代table中的各个元素,同时递归的写出各个字段的value。 44 --由此可以看出,这个简单例子可以支持嵌套的table。 45 for k,v in pairs(o) do 46 --这样做是为了防止k中包含非法的Lua标识符。 47 io.write(" ["); serialize(k); io.write("] = ") 48 serialize(v) 49 io.write(",\n") 50 end 51 io.write("}\n") 52 else 53 error("cannot serialize a " .. type(o)) 54 end 55 end 56 57 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 58 元表的应用: 59 Set = {} 60 local mt = {} 61 62 function Set.new(L) 63 local set = {} 64 setmetatable(set,mt) 65 for _,v in pairs(L) do 66 set[v] = true 67 end 68 return set 69 end 70 71 function Set.union(a,b) 72 local cur = {} 73 for i in pairs(a) do 74 cur[i] = true 75 end 76 77 for i in pairs(b) do 78 cur[i] = true 79 end 80 return cur 81 end 82 83 function Set.intersection(a,b) 84 local cur = {} 85 for v in pairs(a) do 86 cur[v] = b[v] 87 end 88 return cur 89 end 90 91 function Set.tostring(set) 92 local l = {} 93 for e in pairs(set) do 94 l[#l+1] = e 95 end 96 return "{"..table.concat(l,",").."}" 97 end 98 99 function Set.print(s) 100 print(Set.tostring(s)) 101 end 102 103 mt.__add = Set.union 104 105 s1 = Set.new({10,20,30,50}) 106 s2 = Set.new({15,25,35,60}) 107 108 s3 = s1+s2 109 Set.print(s3) 110 111 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 112 __newindex元方法与__index类似,__newindex用于更新table中的数据, 113 而__index用于查询table中的数据。当对一个table中不存在的索引赋值时,在Lua中是按照以下步骤进行的: 114 1.Lua解释器先判断这个table是否有元表; 115 2.如果有了元表,就查找元表中是否有__newindex元方法;如果没有元表,就直接添加这个索引,然后对应的赋值; 116 3.如果有这个__newindex元方法,Lua解释器就执行它,而不是执行赋值; 117 4.如果这个__newindex对应的不是一个函数,而是一个table时,Lua解释器就在这个table中执行赋值,而不是对原来的table。 118 119 __index 例子: 120 Windows = {} 121 122 Windows.default = { 123 x = 0,y = 0,with = 100,heigh = 200, 124 color = { 125 r = 255, g = 255, b = 255 126 } 127 } 128 129 function Windows.tostring(s) 130 if type(s) == "number" then 131 io.write(s) 132 elseif type(s) == "string" then 133 io.write(string.format("%q",s)) 134 elseif type(s) == "table" then 135 io.write("{") 136 for key,value in pairs(s) do 137 io.write("["); io.write(Windows.tostring(key)); io.write("] = ") 138 io.write(Windows.tostring(value)) 139 io.write(",\n") 140 end 141 io.write("}") 142 else 143 error("cannot tostring!!!"); 144 end 145 end 146 147 function Windows.print(s) 148 return print(Windows.tostring(s)) 149 end 150 Windows.mt = {} -- 创建元表 151 152 function Windows.new(o) 153 setmetatable(o,Windows.mt) 154 return o 155 end 156 157 Windows.mt.__index = function (table ,key) 158 return Windows.default[key] 159 end 160 161 local win = Windows.new{x = 10, y = 20 } 162 163 164 Windows.print(win.x) 165 Windows.print(win.with) 166 Windows.print(win.color) 167 168 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 169 实现类和对象的例子: 170 p中有没有talk这个键? 有 --> 返回talk对应的值 171 | 172 没有 173 | 174 p中是否设置过metatable? 否 --> 返回nil 175 | 176 有 177 | 178 在p的metatable中有没有__index这个键? 没有 --> 返回nil 179 | 180 有 181 | 182 在p的metatable中的__index这个键对应的表中有没有talk这个键? 没有 --> 返回nil 183 | 184 有,返回getmetatable(p).__index.talk 185 186 187 Person = {name = "我是一个懒人"} --类 188 189 Person.__index = Person --重定义元表的索引 设置Person类的__index为自己 190 function Person:talk(words)--类的一个方法 191 print(self.name.." 说:"..words) 192 end 193 194 function Person:create(name)--构造函数一样 195 local p = {} 196 setmetatable(p,Person) --设置了p的元方法 197 p.name = name 198 return p 199 end 200 201 local pa = Person:create("路人甲A") --创建一个对象 202 local pb = Person:create("路人甲B") 203 204 pa:talk("hello") 205 pb:talk("sb") 206 207 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 208 类的继承的一个例子:必须理解setmetatable,__index的过程。 209 210 -- http://blog.csdn.net/losophy/article/details/20311387 211 A = {} --基类A 212 213 function A:new(o) --构造方法 214 o = o or {} --如果为nil 则赋值为{} 215 setmetatable(o,self) --设置元方法,确定在谁那寻找子类,没有的方法 216 self.__index = self --这个很重要。所以理解。 217 return o 218 end 219 220 function A:funName() 221 print("A") 222 end 223 224 B = A:new() 225 B:funName() 226 227 C = B:new() 228 229 function B:funName() 230 print("B") 231 end 232 233 C:funName() 234 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 235 使用__newindex设置只读模式,牛气 236 local function readOnly(t) 237 local newT = {} 238 local mt = { 239 __index = t, 240 __newindex = function() 241 error("别修改我!我是只读的!") 242 end 243 } 244 setmetatable(newT, mt) 245 return newT 246 end 247 local days = readOnly({"星期一", "星期二", "星期日"}) 248 249 print(days[2]) 250 days[1]="hehe" --但调用次赋值的时候,就会找到__newindex,从而被禁止 251 252 ______________________________________________________________ 253 a.首先,readOnly会创建一个新的table,然后把我们传进去的table作为__index元方法。 254 b.元表里还增加了__newindex,用来阻止不存在字段的赋值操作。 255 c.readOnly返回的table已经不是我们原来的table了,它是一个空的table,但是它被设置了一个新的元表。 256 d.开始对days执行赋值操作:days[2] = “星期三哪去了啊?” 。 257 e.days是一个空的table,所以它不存在这个字段,也因此,会调用__newindex元方法,赋值失败。 258 f.如果只是调用days,不进行赋值,如:print(days[2]); 则能正常输出字段值,因为days的元表里有__index元方法。虽然days中不存在2这个字段,但是可以通过__index找到这个字段。 259 总而言之,最终,days成为了一个只可以读取,不能进行赋值操作的table。 260 261 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 262 解释__newindex的作用 263 a.如果__newindex是一个函数,则在给table不存在的字段赋值时,会调用这个函数。 264 b.如果__newindex是一个table,则在给table不存在的字段赋值时,会直接给__newindex的table赋值。 265 266 local smartMan = { 267 name = "hxl", 268 money = 9000, 269 hello = function() 270 print("hxl ni hao") 271 end 272 } 273 274 local t = {} 275 276 local mt = { 277 __index = smartMan, 278 __newindex = function(table,key,value) 279 print("key".."不要试图修改我,已经被禁止了!") 280 end 281 } 282 283 setmetatable(t,mt) 284 285 print(t.name) 286 print(t.money) 287 t.hello() 288 t.hello = "heh" 289 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 290 __index 和 __newindex的一个很牛气的例子 291 local smartMan = { 292 name = "none", 293 } 294 295 local other = { 296 name = "大家好,我是很无辜的table" 297 } 298 299 local t1 = {}; 300 301 local mt = { 302 __index = smartMan, 303 __newindex = other 304 } 305 306 setmetatable(t1, mt); 307 308 print("other的名字,赋值前:" .. other.name); 309 t1.name = "小偷"; 310 print("other的名字,赋值后:" .. other.name); 311 print("t1的名字:" .. t1.name); 312 结果: 313 [LUA-print] other的名字,赋值前:大家好,我是很无辜的table 314 [LUA-print] other的名字,赋值后:小偷 315 [LUA-print] t1的名字:none 316 说明:修该的时候只会修改__newindex里面的指定的地方值, 317 查询的时候只会读出 __index里面的值. 318 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4.
1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 Lua实现多重继承: 3 4 5 function search(classes, key)--查询函数 6 for i = 1, #classes do 7 local value = classes[i][key]; 8 if value ~= nil then 9 return value; 10 end 11 end 12 end 13 14 function createClass(...) --可变参数 15 local parents = {...}; --保存它的可变参数 16 local child = {}; 17 18 -- 设置类的元表,如果元表已经设置,就去元表里看看有没有设置__index,找有没有对应的key值. 19 setmetatable(child, { 20 __index = function(table, key) 21 return search(parents, key); 22 end 23 }) 24 25 -- 给类新增一个new函数,用于创建对象 26 function child:new() 27 o = {}; 28 setmetatable(o, child);--设置元表,并且在自己的地方寻找有木有相对于的key值 29 child.__index = child;--设置元表,并且在自己的地方寻找有木有相对于的key值 30 return o; 31 end 32 33 -- 返回这个继承了多个类的子类 34 return child; 35 end 36 37 38 --一个精灵类 39 TSprite = {} 40 function TSprite:hello() 41 print("谁跟你hello!"); 42 end 43 44 function TSprite:new() 45 o = {} 46 setmetatable(o, self); 47 self.__index = self; 48 return o; 49 end 50 51 -- 一个子弹类 52 TBullet = {} 53 function TBullet:fire() 54 print("别动,再动我就瞄不准了!"); 55 end 56 function TBullet:new() 57 o = {} 58 setmetatable(o, self); 59 self.__index = self; 60 return o; 61 end 62 63 -- 继承了两个类的子类 64 local BulletSprite = createClass(TSprite, TBullet);--传入这两个table,返回对应的child 65 66 -- 子类的对象 67 local bSprite = BulletSprite:new(); 68 bSprite:hello(); 69 --[[子类对象调用hello方法,会去bSprite中寻找, 70 发现没有,那么此时没有就去看看 bSprite有没有设置元表有的,去元表中看有没有设置__index 71 发现也是有的,就调用它对应的方法,便进入了serch了。便可以找到了 72 --]] 73 bSprite:fire(); 74 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 75 弱引用: 76 1)key值弱引用,也就是刚刚说到的情况,只要其他地方没有对key值引用, 77 那么,table自身的这个字段也会被删除。设置方法:setmetatable(t, {__mode = “k”}); 78 2)value值弱引用,情况类似,只要其他地方没有对value值引用, 79 那么,table的这个value所在的字段也会被删除。设置方法:setmetatable(t, {__mode = “v”}); 80 3)key和value弱引用,规则一样,但是key和value都同时生效, 81 任意一个起作用时都会导致table的字段被删除。设置方法:setmetatable(t, {__mode = “kv”}); 82 83 当然,这里所说的被删除,是指在Lua执行垃圾回收的时候,并不一定是立刻生效的。 84 我们刚刚只是为了测试,而强制执行了垃圾回收。 85 86 t = {}; 87 88 -- 给t设置一个元表,增加__mode元方法,赋值为“k” 89 setmetatable(t, {__mode = "k"}); 90 91 -- 使用一个table作为t的key值 92 key1 = {name = "key1"}; 93 t[key1] = 1; 94 95 -- 又使用一个table作为t的key值 96 key2 = {name = "key2"}; 97 t[key2] = 1; 98 99 t = {} 100 key1,key2 = t,t 101 102 -- 强制进行一次垃圾收集 103 collectgarbage(); 104 105 for key, value in pairs(t) do 106 print(key.name .. ":" .. value); 107 end 108 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~