美文网首页js css html
lua--协程、异常处理、面向对象

lua--协程、异常处理、面向对象

作者: aruba | 来源:发表于2022-06-22 13:45 被阅读0次

    一、协程

    协程是单核的,是一个线程下执行的,所以每一时刻只会有一个协程在运行。线程一般由cpu调度,协程由用户调用

    1. 协程创建

    协程创建有两种方式

    1.1 coroutine.create

    coroutine.create:创建协程 coroutine.resume:启动协程

    -- 创建协程
    cor1 = coroutine.create(
            function(a,b)
                    print(a+b)
            end
    )
    
    -- 启动协程
    coroutine.resume(cor1,1,2)
    

    运行结果:

    1.2 coroutine.wrap

    coroutine.wrap:创建协程 协程变量(入参):启动协程

    -- 创建协程2
    cor2 = coroutine.wrap(
            function(a)
                    print(a)
            end
    )
    
    cor2(5)
    

    运行结果:

    2. 协程的暂停和继续

    协程还可以通过代码暂停执行和继续执行

    2.1 暂停协程

    coroutine.yield:协程暂停

    在定义协程的function中,执行暂停方法:

    -- 暂停、继续协程
    cor3 = coroutine.create(
            function()
                    print('准备暂停')
                    coroutine.yield()
                    print('继续执行')
            end
    )
    
    coroutine.resume(cor3)
    

    运行结果:

    可以看到print('继续执行')并没有执行

    2.2 继续协程

    coroutine.resume:协程继续

    再次调用coroutine.resume,就可以继续执行协程了:

    -- 暂停、继续协程
    cor3 = coroutine.create(
            function()
                    print('准备暂停')
                    coroutine.yield()
                    print('继续执行')
            end
    )
    
    coroutine.resume(cor3)
    -- 继续执行协程
    coroutine.resume(cor3)
    

    运行结果:

    3. 返回值和入参

    协程执行也有返回值,并且每次执行结束或暂停都有返回值,每次继续都有不同的入参

    3.1 执行结束返回值

    一个协程正常执行结束,如果不指定return,那么默认会返回一个true

    -- 协程执行结束返回值
    cor4 = coroutine.create(
            function()
                    print("结束啦")
            end
    )
    
    
    -- 接收返回值
    ret4 = coroutine.resume(cor4)
    print(ret4)
    

    运行结果:

    如果协程运行结束后再次运行,那么将返回false

    -- 协程执行结束返回值
    cor4 = coroutine.create(
            function()
                    print("结束啦")
            end
    )
    
    
    -- 接收返回值
    ret4 = coroutine.resume(cor4)
    print(ret4)
    print(coroutine.resume(cor4))
    

    运行结果:

    如果指定return,那么将多返回值返回,下面是使用return的情况:

    -- 协程执行结束返回值
    cor4 = coroutine.create(
            function()
                    print("结束啦")
                    return '哈哈'
            end
    )
    
    
    -- 接收返回值
    ok,ret4 = coroutine.resume(cor4)
    print(ok,ret4)
    

    运行结果:

    3.2 暂停返回值

    上面使用协程暂停和继续时,我们知道了,每次在定义协程的function中调用yield,都必须再次调用resume才能继续执行协程,而接收协程返回值的方法就是resume,所以猜想每次yield,都会有返回值,下面就来测试下

    打印两次执行协程的返回值:

    -- 协程暂停返回值
    cor5 = coroutine.create(
            function(a)
                    print('接收参数:',a)
                    -- 暂停协程
                    coroutine.yield()
            end
    )
    
    print(coroutine.resume(cor5,10))
    print(coroutine.resume(cor5,10))
    

    运行结果:

    yield方法还可以传入参数,作为每次暂停的返回值:

    -- 协程暂停返回值
    cor5 = coroutine.create(
            function(a)
                    print('接收参数:',a)
                    -- 暂停协程
                    coroutine.yield('哈哈')
            end
    )
    
    print(coroutine.resume(cor5,10))
    print(coroutine.resume(cor5,10))
    

    运行结果:

    3.3 继续执行入参

    我们的参数都是通过resume方法传入的,既然yield可以有暂停协程的返回值,那么每次resume也可以传入新的入参:

    -- 协程暂停返回值
    
    -- 协程暂停、继续返回值
    cor5 = coroutine.create(
            function(a)
                    print('第一次接收参数:',a)
                    -- 暂停协程,并接收新的参数
                    i,k = coroutine.yield('哈哈')
                    print('第二次接收参数:',i,k)
            end
    )
    
    print(coroutine.resume(cor5,10))
    print(coroutine.resume(cor5,20,30))
    

    运行结果:

    4. 协程的状态

    一个协程从定义,到运行,到暂停,到执行结束,它的状态如何变化呢?下面就来探究协程的状态

    coroutine.status可以查看传入协程的状态:

    -- 协程状态
    cor6 = coroutine.create(
            function()
                    print('运行时状态:',coroutine.status(cor6))
                    coroutine.yield()
                    print('恢复运行时状态:',coroutine.status(cor6))
            end
    )
    
    print('运行前状态:',coroutine.status(cor6))
    coroutine.resume(cor6)
    print('暂停后状态:',coroutine.status(cor6))
    coroutine.resume(cor6)
    print('运行完成后状态:',coroutine.status(cor6))
    

    运行结果:

    所以上面我们称为暂停协程是不确切的,应该称为挂起,可以看到协程有三种状态:挂起、运行、死亡

    5. 协程实现生产者消费者模式

    协程可以被挂起和继续,那么实现生产者和消费者就简单多了,消费者执行生产者协程生产,生产者协程生产完成后,将自身挂起,将产品作为返回值返回,消费者进行消费即可

    produce = coroutine.create(
            function()
                    local i = 0
                    while(i < 10) do
                            i = i + 1
                            print('生产者生产:',i)
                            -- 挂起协程
                            coroutine.yield(i)
                    end
            end
    )
    
    function consumer()
            while(true) do
                    -- 执行协程
                    ok,ret = coroutine.resume(produce)
                    if ok and ret ~= nil then
                            print('消费者消费:',ret)
                    else
                            break
                    end
            end
    end
    
    -- 开始程序
    consumer()
    

    运行结果:

    二、异常处理

    异常分为两种,编译异常和运行时异常

    1. 编译异常

    当我们语法出现错误时,执行lua脚本时就会报错,这种异常我们无法捕获,只有将代码修改正确

    a == 1
    if a then
            print(a)
    end
    

    运行结果:

    下面我们只讨论运行时异常

    2. 抛出异常

    抛出异常有两种方式

    2.1 assert断言

    asser判断第一个参数是否为false,如果是false,则抛出异常,信息为第二个参数

    -- assert
    function requireNotNil(a)
            assert(a,'必须不为空')
    end
    
    requireNotNil()
    

    运行结果:

    2.2 error

    error直接抛出一个异常

    -- error
    function requireNumber(a)
            if type(a) ~= type(1) then
                    error("必须是number类型")
            end
    end
    
    requireNumber('zhangsan')
    

    运行结果:

    3. 处理异常

    如果不处理异常,那么程序将会退出,处理异常有两种方式

    3.1 pcall

    pcall可以测试函数的执行,第一个参数为函数名,后面参数为入参,如果没有异常,那么返回true和函数返回值,否则返回false和异常:

    
    -- error
    function requireNumber(a)
            if type(a) ~= type(1) then
                    error("必须是number类型")
            end
    
            return a
    end
    
    -- requireNumber('zhangsan')
    
    -- pcall
    print(pcall(requireNumber,1))
    print(pcall(requireNumber,'1'))
    

    运行结果:

    3.2 xpcall

    xpcall可以处理异常,只允许两个参数,第一个为调用的函数名,第二个为处理异常的function

    -- xpcall
    function handleException(err)
            print('出现异常:',err)
    end
    
    function throwException()
            error('有个异常')
    end
    
    xpcall(throwException,handleException)
    

    运行结果:

    三、面向对象

    lua中面向对象是通过table来实现的,table的元素可以是不同数据类型,也可以是一个函数

    1. 函数类型元素

    给table设置一个函数,有三种方式

    1.1 赋值新值方式

    第一种就是给table赋值新值方式,即初始化和后续新增赋值:

    -- 初始化时定义函数
    user = {
            name = '张三',
            age = 18,
            doSomething = function(name)
                    print(name.."做功课")
            end
    }
    
    user.doSomething(user.name)
    
    -- 后续新增函数
    user.sleep = function(name)
            print(name.."去睡觉")
    end
    
    user.sleep(user.name)
    

    运行结果:

    1.2 table名.函数名方式

    function table名.函数名方式,也可以为table新增一个函数

    -- table.函数方式
    function user.wakeup(name)
            print(name.."醒了")
    end
    user.wakeup(user.name)
    

    运行结果:

    2. 面向对象

    如何让上面的user成为一个类型,被其他变量使用呢?
    答案是结合:和使用元表,在function table名.函数名方式时,将.替换成:,就可以在函数内部使用self来获取自身,此时使用元表的__index,将self和一张空表结合,返回出去,就能得到一张新的usertable

    -- 面向对象
    function user:new()
            u = {}
            setmetatable(u,{__index = self})
    
            return u
    end
    
    lisi = user:new()
    lisi.name = '李四'
    lisi.age = 25
    
    print(lisi.name..lisi.age)
    print(lisi.doSomething(lisi.name))
    print(lisi.sleep(lisi.name))
    

    运行结果:

    相关文章

      网友评论

        本文标题:lua--协程、异常处理、面向对象

        本文链接:https://www.haomeiwen.com/subject/rniyvrtx.html