2.1 表

snippet.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
    ```
  1. 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
    ```
  1. __newindex:用来对表更新
  当你**给表缺少的索引进行赋值时**,解释器就会查找`__newindex` 元方法
  1. __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
    ```
  1. __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
    ```
  1. __call:在 Lua 以函数方式调用主表时,调用元表__call对应的函数
  1. 第一个参数为主表
  2. 后续接可变参数
  ```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
  ```
  1. __tostring:元方法用于修改表的输出行为。以下实例我们自定义了表的输出内容
  ```lua
  local a = {}
  local b = {}
b.__tostring = function (mytable) 
    return "toString方法"
  end
  local c = setmetatable(a, b)
  print(a)  --- toString 方法
  ```
  

2.2 三元表达式

snippet.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 循环表达式

2.4 断言

assert(a, b):a是要检查是否有错误的一个参数,b是a错误时抛出的信息(参数b是可选的)(assert只在debugger模式下有用)

snippet.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")