#### 2.1 表 - `test = { a="1", [4]="2", "3", d=nil, e="5", "6", nil, "7", i={"1"}}` 需要注意是,如果手动给一个值设置数字作为其键,若没有键的单值的索引(从1开始)大于等于前面这个被设置的数字键,则输出的时候会覆盖掉前面的值 如上,设置test[4]=2, 但是单值的数量为4(3,6,nil,7),所以test[4]被后面的7覆盖掉,变成了 test[4]=7 - 元表(metaclass) - `setmetatable(tableA, tableB)`:将tableB设置为tableA的元表,返回值为设置元表后的tableA - `getmetatable(tableA)`:返回tableA的元表,若其没有元表,返回nil - `__index`:用来对表访问 - `__index`的值是一个表 当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的`__index` 键 ```lua local a = {} local b = {} b.__index = {key="value"} setmetatable(a, b) print(a["key"]) --- value -----等价------ setmetatable(a, {__index={key="value"}}) print(a["key"]) --- value ``` - `__index`是一个函数 当你通过键访问table的时候,如果这个键没有值,那么Lua会把table和键分别作为`__index`对应函数的两个参数传递过去 ```lua tableA = nil local fn = function(mytable, key) tableA = mytable if key == "key2" then return "查找的键为key2" else return nil end end local a = {key1 = "value1"} local b = {__index = fn} setmetatable(a, b) print(a.key1, a.key2) --- value1 查找的键为key2 print(tableA==a) --- true (说明函数接受的table是原来的table(a),不是table的metatable(b)) print(tableA==b) --- false ----另一种写法---- a = setmetatable({key1 = "value1"}, { __index = {key2 = "查找的键为key2"}}) print(a.key1, a.key2) --- value1 查找的键为key2 print(tableA==a) --- true (说明函数接受的table是主表,不是元表) print(tableA==b) --- false ``` - `rawget(table, "key")`:让元表的`__index`方法无效 ```lua ----当__index是一个表时,rawget(table, "key")让其无效--- local a = {} local b = {} b.__index = {key="value"} setmetatable(a, b) print(a.key) --- value print(rawget(a, "key")) --- nil ---当__index是一个函数时,rawget(table, "key")让其无效--- local fn = function(mytable, key) return key end local a = {key1 = "value1"} local b = {__index = fn} setmetatable(a, b) print(a.key1, a.key2) --- value1 key2 print(rawget(a, "key1")) --- value1 print(rawget(a, "key2")) --- nil ``` - `__newindex`:用来对表更新 当你**给表缺少的索引进行赋值时**,解释器就会查找`__newindex` 元方法 - `__newindex`是一个表 会直接把值赋给`__newindex`对应的表,而不会对主表进行赋值 ```lua ---对主表不存在的键进行赋值,会触发元表的__newindex方法--- local a = {test="已有的值"} local b = {} b.__newindex = {} setmetatable(a, b) a["key"] = "没有的key进行赋值" print(a["key"]) --- nil print(b["key"]) --- nil print(b.__newindex["key"]) --- "没有的key进行赋值" ---对主表已有的键进行赋值,不会触发元表的__newindex方法--- local a = {test="已有的值"} local b = {} b.__newindex = {} setmetatable(a, b) a["test"] = "改变test的值" print(a["test"]) --- "改变test的值" print(b["test"]) --- nil print(b.__newindex["test"]) --- nil ``` - `__newindex`是一个函数 在`__newindex`中如果对主表中的键进行赋值,要用`rawset`(直接赋值会导致递归) ```lua local fn = function(mytable, k, v) print("k: " .. k) print("v: " .. v) end local a = {test="已有的值"} local b = {} b.__newindex = fn setmetatable(a, b) a["key"] = "没有的key进行赋值" --- k: key --- v: 没有的key进行赋值 print(a["key"]) --- nil print(b["key"]) --- nil print(b["__newindex"]["key"]) -- Error,因为__newindex是个函数,不是表 ---在__newindex中对主表进行修改--- local fn = function(mytable, k, v) local modi_v = "【" ..v.. "】" rawset(mytable, k, modi_v) -- 要用rawset,直接mytable[k]=v会引起递归 end local a = {test="已有的值"} local b = {} b.__newindex = fn setmetatable(a, b) a["key"] = "没有的key进行赋值" --- k: key --- v: 没有的key进行赋值 print(a["key"]) --- 【没有的key进行赋值】 print(b["key"]) --- nil ``` - `__call`:在 Lua 以函数方式调用主表时,调用元表`__call`对应的函数 - 第一个参数为主表 - 后续接可变参数 ```lua local a = {} local b = {} b.__call = function (mytable, ...) local t = {...} for i, v in pairs(t) do print(v) end return "__call方法" end local c = {10, 20, 30} setmetatable(a, b) print(a(1)) --- 1 print(a(1, 2, 3)) --- 1 2 3 ``` - `__tostring`:元方法用于修改表的输出行为。以下实例我们自定义了表的输出内容 ```lua local a = {} local b = {} b.__tostring = function (mytable) return "toString方法" end local c = setmetatable(a, b) print(a) --- toString 方法 ``` #### 2.2 三元表达式 ```lua local thing = condition and if_true or if_false ---------------等价于--------------- local thing = nil if condition then thing = if_true else thing = if_false end ``` #### 2.3 循环表达式 - `pairs`:输出所有非nil对象 - 键值对、单值,`pairs`都可以遍历到,`pairs`首先给所有非键值对,按顺序赋一个索引作为key值,如下文的"3"、"6",nil, "7"被分别赋为"1", "2", "3", "4",然后输出所有键值对(随机顺序,同时跳过nil) ```lua local test = { a="1", [4]="2", "3", d=nil, e="5", "6", nil, "7"} for k, v in pairs(test) do print(k..v) end --[[输出 13 26 47 -- 这里是7不是2,详见Lua中关于表的定义 e5 a1 ]] ``` - `ipairs` :输出所有非键值对,遇到nil停止 ```lua local test = { a="1", [4]="2", "3", d=nil, e="5", "6", nil, "7"} for i, v in ipairs(test) do print(i..v) end --[[输出 13 26 ]] --因为d=nil, 是键值对,本身就不会被考虑进去,所以在剩下的 3,6,nil,7中,会输出到6,然后遇到nil终止 ``` #### 2.4 断言 `assert(a, b)`:a是要检查是否有错误的一个参数,b是a错误时抛出的信息(参数b是可选的)(assert只在debugger模式下有用) ```lua print("enter a number:") n = io.read("*number") if not n then error("invalid input") end ---↓等价于↓--- print("enter a number:") n = assert(io.read("*number"), "invalid input") ```