cat
Shioho

# String

string 可支持多行输入,格式为 [[ xxxx ]]

html = [[
<html>
<head></head>
<body>
    <a href="http://www.runoob.com/">菜鸟教程</a>
</body>
</html>
]]

# 迭代器

pairs 迭代 table,会遍历表中所有的 key 和 value 值,不论这个 value 值是否为 nil

ipairs 迭代 table,会按照索引为 1 开始,遇到 nil 时就会停止当前遍历,适用于遍历数组形式的 table

自定义迭代函数,下方自定义了一个返回每次索引平方的迭代函数

-- 迭代函数
function square(cnt,idx)
    if(cnt>=idx)then
       return nil
    else
        idx=idx+1
        return idx*idx
    end
end
-- 使用
for i in square,4,0 do
    print(i)
end
--[[ 输出结果为
    1
    4
    9
    16
]]--

# 元表

设置某个表的元表

table = {1,2,3}
-- 元表
metatable = {}
-- 如果元表中设置了 __metatable 键值,那么就禁止用户访问该元表并修改该元表内的元素
-- 如果元表 (metatable) 中存在 __metatable 键值,setmetatable 会失败
table= setmetatable(table,metatable)

获取某个表的元表

-- 如果元表中存在 __metatable, 那么返回的是 __metatable 的 value 值,否则返回的是 metatable 的内存地址
metatable = getmetatable(table)

# __index 元方法

当访问表中的某个索引时,若该表不存在该索引则生效。如果__index 包含一个函数的话,Lua 就会调用那个函数,table 和键会作为参数传递给函数。__index 元方法查看表中元素是否存在,如果不存在,返回结果为 nil;如果存在则由__index 返回结果

mytable = setmetatable({key1 = "value1"}, 
{ 
    __index = function(mytable, key)  
        if key == "key2" then    
            return "metatablevalue"  
        else    
            return nil  
        end 
    end
 })
print(mytable.key1,mytable.key2)
-- 输出结果为 value1    metatablevalue

# __newindex 元方法

当表添加新的键值对时生效。在对新索引键(newkey)赋值时(mytable.newkey = "新值 2"),会调用元方法,而不进行赋值。而如果对已存在的索引键(key1),则会进行赋值,而不调用元方法__newindex。

mytable = setmetatable({key1 = "value1"}, {
  __newindex = function(mytable, key, value)
     rawset(mytable, key, "\""..value.."\"")
     -- 不能用 mytable [key]=value, 因为这么做会重新出发该方法,造成死循环
  end
})
mytable.key1 = "new value"
mytable.key2 = 4
print(mytable.key1,mytable.key2)
-- 输出结果为 new value    "4"

# 为表添加操作符

两个表进行运算时触发 ,如 tab3=tab1+tab2

模式描述
__add对应的运算符 '+'
__sub对应的运算符 '-'
__mul对应的运算符 '*'
__div对应的运算符 '/'
__mod对应的运算符 '%'
__unm对应的运算符 '-'
__concat对应的运算符 '..'
__eq对应的运算符 '=='
__lt对应的运算符 '<'
__le对应的运算符 '<='

以下演示了 __add 操作

function table_maxn(t)
    local mn = 0
    for k, v in pairs(t) do
        if mn < k then
            mn = k
        end
    end
    return mn
end
-- 两表相加操作
mytable = setmetatable({ 1, 2, 3 }, {
  __add = function(mytable, newtable)
    for i = 1, table_maxn(newtable) do
      table.insert(mytable, table_maxn(mytable)+1,newtable[i])
    end
    return mytable
  end
})
secondtable = {4,5,6}
mytable = mytable + secondtable
        for k,v in ipairs(mytable) do
print(k,v)
end
--[[
以上实例执行输出结果为:
1    1
2    2
3    3
4    4
5    5
6    6
]]--

# __call 元方法

当表像一个方法一样调用时生效,如 tab ()

function table_maxn(t)
    local mn = 0
    for k, v in pairs(t) do
        if mn < k then
            mn = k
        end
    end
    return mn
end
-- 定义元方法__call
mytable = setmetatable({10}, {
  __call = function(mytable, newtable)
        sum = 0
        for i = 1, table_maxn(mytable) do
                sum = sum + mytable[i]
        end
    for i = 1, table_maxn(newtable) do
                sum = sum + newtable[i]
        end
        return sum
  end
})
newtable = {10,20,30}
print(mytable(newtable))
-- 以上实例执行输出结果为:70

# __tostring 元方法

__tostring 元方法用于修改表的输出行为。如 print (tab), 默认输出的是 tab 的地址,__tostring 可以对输出进行修改

mytable = setmetatable({ 10, 20, 30 }, {
  __tostring = function(mytable)
    sum = 0
    for k, v in pairs(mytable) do
                sum = sum + v
        end
    return "表所有元素的和为 " .. sum
  end
})
print(mytable)
-- 以上输出结果为: 表所有元素的和为 60

# 面向对象

构建一个继承代码

Person = {name="aaa",age=99}
--: 的定义类似于 Person.eat (Person), 这样就可以在内部调用 self
Person:eat = function()
    --self 就是这个表本身
    print(self.name.."在吃饭")
end
-- 这个方法等于构造函数,可传入一个有数据的表 o
Person:New = function(o)
    -- 声明一个空表,用于存新值
    -- 要注意设置为 local 防止外部调用
    local t = o or {}
    -- 将 Person 表设置为 t 表的元表,这样 t 表就能访问到元表的数据
    setmetatable(t,self)
    -- 因为返回值为 t,所以当 t 表访问 key 值时,会去判断 self 是否存在该 key,如果不存在,就会设置到 t 表中,不会影响元表数据
    self.__index=self
    return t
end
-- 生成一个 Student 继承 Person
Student = Person:New()
-- 会存在新表 t 中生成这个 keyValue
Student.grade = 1
-- 生成一个新对象
stu1 = Student:New()
stu1:eat() -- 输出  aaa 在吃饭
stu1.grade -- 输出 1

# 协程

lua 里的协程拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西

方法描述
coroutine.create()创建 coroutine,返回 coroutine, 参数是一个函数,新创建的协程并不会运行,而是处于挂起状态,当和 resume 配合使用的时候就唤醒函数调用
coroutine.resume()重启 coroutine,和 create 配合使用
coroutine.yield()挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果
注:yield 的返回值也是 resume 传入的参数
coroutine.status()查看 coroutine 的状态
注:coroutine 的状态有三种:dead,suspended,running
coroutine.wrap()创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复
coroutine.running()返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用 running 的时候,就是返回一个 coroutine 的线程号

# 案例

function foo (a)
    print("foo 函数输出", a)
    return coroutine.yield(2 * a) -- 返回  2*a 的值
end
 
co = coroutine.create(function (a , b)
    print("第一次协同程序执行输出", a, b) -- co-body 1 10
    local r = foo(a + 1)    -- 第一次执行完会阻塞在这里,这时 r 还未赋值
     
    print("第二次协同程序执行输出", r) -- 这里的 r 值为 coroutine.resume 调用时传入的参数
    local r, s = coroutine.yield(a + b, a - b)  -- a,b 的值为第一次调用协同程序时传入
     
    print("第三次协同程序执行输出", r, s)
    return b, "结束协同程序"                   -- b 的值为第二次调用协同程序时传入
end)
       
print("main", coroutine.resume(co, 1, 10)) -- true, 4
print("--分割线----")
print("main", coroutine.resume(co, "r")) -- true 11 -9
print("---分割线---")
print("main", coroutine.resume(co, "x", "y")) -- true 10 end
print("---分割线---")
print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine
print("---分割线---")
  • 输出结果为:

第一次协同程序执行输出 1 10
foo 函数输出 2
main true 4
-- 分割线 ----
第二次协同程序执行输出 r
main true 11 -9
--- 分割线 ---
第三次协同程序执行输出 x y
main true 10 结束协同程序
--- 分割线 ---
main false cannot resume dead coroutine
--- 分割线 ---

  • 运行过程

调用 resume,将协同程序唤醒,resume 操作成功返回 true,否则返回 false;
协同程序运行;
运行到 yield 语句;
yield 挂起协同程序,第一次 resume 返回;(注意:此处 yield 返回,参数是 resume 的参数)
第二次 resume,再次唤醒协同程序;(注意:此处 resume 的参数中,除了第一个参数,剩下的参数将作为 yield 的参数)
yield 返回;
协同程序继续运行;
如果使用的协同程序继续运行完成后继续调用 resume 方法则输出:cannot resume dead coroutine

# 注意事项

# Table 相关

lua 中的 table 创建数组时第一个索引 key 为 1,而不是 0

#在获取 table 的长度时实际上获取的是数组最大索引的 key,而不是数量,如

tab = {1,2,3}
    #tab -- 这时的值为 3
    
    tab = {key1="val1",key2="val2"}
    #tab -- 这时的值为 0
    
    tab = {}
    tab[1]=10
    tab[2]=20
    tab[10]=100
    #tab -- 这时的值为 10

lua 中数组的索引可以设置为负数,如

tab={}
tab[-5] = 10
print(tab[-5]) -- 这是合法的

当一个 table 被其他变量也引用时,只有将这些变量都置空才会释放改表的内存,如

tab1 = {1,2,3}
tab2 = tab1
tab1 = nil   --{1,2,3} 内存并不会释放,tab1 变量释放了
tab2 = nil -- 引用全部清除,{1,2,3} 内存也被释放

table 数组的数据移除如果直接让改索引等于 nil,那么该索引后面的值的索引并不会 - 1,而只是该索引值变成 nil,如

tab = {1,2,3}
tab[2]=nil -- 这时 tab 实际内容为 {1,nil,3}
-- 如果要彻底移除,可以使用 table.remove
table.remove(tab,2) -- 这时 tab 实际内容为 {1,3}

# If 相关

在 if 判断时 0 代表的是 true,除了 false 和 nil 代表 false 外,其他代表的都是 true

# Function 相关

# 可选参数

在获取一个函数的所有可选参数时,可以通过 arg 字段来获取,但这个字段的最后一位会保存当前可选参数的参数总个数,所以遍历的时候会多遍历一次。如果要过滤这个参数数量,那么可以声明一个局部变量对参数进行转存,如 local args = {...} , 如果要获取参数个数的话可以通过 cnt = #args 来获得

# 函数中 "." 和 ":" 的区别

在 lua 中使用 “:” 定义的函数会自动传入一个名为 self 的变量,这个变量是隐含的,self 同 c++ 中的 this 一样,表示当前对象的指针:而 “.” 定义的函数中没有 self。

# String 相关

print 输出字符串数字相加会进行算数运算,如

print("2"+"6") -- 输出值为 8
print("2"+6) -- 输出值为 8
print("2+6") -- 输出值为 2+6

#在获取包含中文 string 时,一个中文占 2 字节,返回的是字节数,如

#"abcd"  -- 长度为 4
#"哈哈ab" -- 长度为 6
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

汘帆 微信

微信

汘帆 支付宝

支付宝