前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >lua--协程、异常处理、面向对象

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

作者头像
aruba
发布2022-06-27 13:03:49
5480
发布2022-06-27 13:03:49
举报
文章被收录于专栏:android技术android技术

一、协程

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

1. 协程创建

协程创建有两种方式

1.1 coroutine.create

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

代码语言:javascript
复制
-- 创建协程
cor1 = coroutine.create(
        function(a,b)
                print(a+b)
        end
)

-- 启动协程
coroutine.resume(cor1,1,2)

运行结果:

1.2 coroutine.wrap

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

代码语言:javascript
复制
-- 创建协程2
cor2 = coroutine.wrap(
        function(a)
                print(a)
        end
)

cor2(5)

运行结果:

2. 协程的暂停和继续

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

2.1 暂停协程

coroutine.yield:协程暂停

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

代码语言:javascript
复制
-- 暂停、继续协程
cor3 = coroutine.create(
        function()
                print('准备暂停')
                coroutine.yield()
                print('继续执行')
        end
)

coroutine.resume(cor3)

运行结果:

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

2.2 继续协程

coroutine.resume:协程继续

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

代码语言:javascript
复制
-- 暂停、继续协程
cor3 = coroutine.create(
        function()
                print('准备暂停')
                coroutine.yield()
                print('继续执行')
        end
)

coroutine.resume(cor3)
-- 继续执行协程
coroutine.resume(cor3)

运行结果:

3. 返回值和入参

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

3.1 执行结束返回值

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

代码语言:javascript
复制
-- 协程执行结束返回值
cor4 = coroutine.create(
        function()
                print("结束啦")
        end
)


-- 接收返回值
ret4 = coroutine.resume(cor4)
print(ret4)

运行结果:

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

代码语言:javascript
复制
-- 协程执行结束返回值
cor4 = coroutine.create(
        function()
                print("结束啦")
        end
)


-- 接收返回值
ret4 = coroutine.resume(cor4)
print(ret4)
print(coroutine.resume(cor4))

运行结果:

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

代码语言:javascript
复制
-- 协程执行结束返回值
cor4 = coroutine.create(
        function()
                print("结束啦")
                return '哈哈'
        end
)


-- 接收返回值
ok,ret4 = coroutine.resume(cor4)
print(ok,ret4)

运行结果:

3.2 暂停返回值

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

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

代码语言:javascript
复制
-- 协程暂停返回值
cor5 = coroutine.create(
        function(a)
                print('接收参数:',a)
                -- 暂停协程
                coroutine.yield()
        end
)

print(coroutine.resume(cor5,10))
print(coroutine.resume(cor5,10))

运行结果:

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

代码语言:javascript
复制
-- 协程暂停返回值
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也可以传入新的入参:

代码语言:javascript
复制
-- 协程暂停返回值

-- 协程暂停、继续返回值
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可以查看传入协程的状态:

代码语言:javascript
复制
-- 协程状态
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. 协程实现生产者消费者模式

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

代码语言:javascript
复制
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脚本时就会报错,这种异常我们无法捕获,只有将代码修改正确

代码语言:javascript
复制
a == 1
if a then
        print(a)
end

运行结果:

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

2. 抛出异常

抛出异常有两种方式

2.1 assert断言

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

代码语言:javascript
复制
-- assert
function requireNotNil(a)
        assert(a,'必须不为空')
end

requireNotNil()

运行结果:

2.2 error

error直接抛出一个异常

代码语言:javascript
复制
-- error
function requireNumber(a)
        if type(a) ~= type(1) then
                error("必须是number类型")
        end
end

requireNumber('zhangsan')

运行结果:

3. 处理异常

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

3.1 pcall

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

代码语言:javascript
复制
-- 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

代码语言:javascript
复制
-- xpcall
function handleException(err)
        print('出现异常:',err)
end

function throwException()
        error('有个异常')
end

xpcall(throwException,handleException)

运行结果:

三、面向对象

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

1. 函数类型元素

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

1.1 赋值新值方式

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

代码语言:javascript
复制
-- 初始化时定义函数
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新增一个函数

代码语言:javascript
复制
-- table.函数方式
function user.wakeup(name)
        print(name.."醒了")
end
user.wakeup(user.name)

运行结果:

2. 面向对象

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

代码语言:javascript
复制
-- 面向对象
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))

运行结果:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-06-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、协程
    • 1. 协程创建
      • 1.1 coroutine.create
      • 1.2 coroutine.wrap
    • 2. 协程的暂停和继续
      • 2.1 暂停协程
      • 2.2 继续协程
    • 3. 返回值和入参
      • 3.1 执行结束返回值
    • 3.2 暂停返回值
      • 3.3 继续执行入参
        • 4. 协程的状态
          • 5. 协程实现生产者消费者模式
          • 二、异常处理
            • 1. 编译异常
              • 2. 抛出异常
                • 2.1 assert断言
                • 2.2 error
              • 3. 处理异常
                • 3.1 pcall
                • 3.2 xpcall
            • 三、面向对象
              • 1. 函数类型元素
                • 1.1 赋值新值方式
                • 1.2 table名.函数名方式
              • 2. 面向对象
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档