使用lua实现try-catch异常捕获
lua原生并没有提供try-catch的语法来捕获异常处理,但是提供了pcall/xpcall等接口,可在保护模式下执行lua函数。
因此,可以通过封装这两个接口,来实现try-catch块的捕获机制。
我们可以先来看下,封装后的try-catch使用方式:
try
{
-- try 代码块
function ()
error("error message")
end,
-- catch 代码块
catch
{
-- 发生异常后,被执行
function (errors)
print(errors)
end
}
}
上面的代码中,在try块内部认为引发了一个异常,并且抛出错误消息,在catch中进行了捕获,并且将错误消息进行输出显示。
这里除了对pcall/xpcall进行了封装,用来捕获异常信息,还利用了lua的函数调用语法特性,在只有一个参数传递的情况下,lua可以直接传递一个table类型,并且省略()
其实try后面的整个{...} 都是一个table而已,作为参数传递给了try函数,其具体实现如下:
function try(block)
-- get the try function
local try = block[1]
assert(try)
-- get catch and finally functions
local funcs = block[2]
if funcs and block[3] then
table.join2(funcs, block[2])
end
-- try to call it
local ok, errors = pcall(try)
if not ok then
-- run the catch function
if funcs and funcs.catch then
funcs.catch(errors)
end
end
-- run the finally function
if funcs and funcs.finally then
funcs.finally(ok, errors)
end
-- ok?
if ok then
return errors
end
end
可以看到这里用了pcall来实际调用try块里面的函数,这样就算函数内部出现异常,也不会中断程序,pcall会返回false表示运行失败
并且返回实际的出错信息,如果想要自定义格式化错误信息,可以通过调用xpcall来替换pcall,这个接口与pcall相比,多了个错误处理函数:
local ok, errors = xpcall(try, debug.traceback)
你可以直接传入debug.traceback,使用默认的traceback处理接口,也可以自定义一个处理函数:
-- traceback
function my_traceback(errors)
-- make results
local level = 2
while true do
-- get debug info
local info = debug.getinfo(level, "Sln")
-- end?
if not info or (info.name and info.name == "xpcall") then
break
end
-- function?
if info.what == "C" then
results = results .. string.format(" [C]: in function '%s'\n", info.name)
elseif info.name then
results = results .. string.format(" [%s:%d]: in function '%s'\n", info.short_src, info.currentline, info.name)
elseif info.what == "main" then
results = results .. string.format(" [%s:%d]: in main chunk\n", info.short_src, info.currentline)
break
else
results = results .. string.format(" [%s:%d]:\n", info.short_src, info.currentline)
end
-- next
level = level + 1
end
-- ok?
return results
end
-- 调用自定义traceback函数
local ok, errors = xpcall(try, my_traceback)
回到try-catch上来,通过上面的实现,会发现里面其实还有个finally的处理,这个的作用是对于try{}代码块,不管是否执行成功,都会执行到finally块中
也就说,其实上面的实现,完整的支持语法是:try-catch-finally模式,其中catch和finally都是可选的,根据自己的实际需求提供
例如:
try
{
-- try 代码块
function ()
error("error message")
end,
-- catch 代码块
catch
{
-- 发生异常后,被执行
function (errors)
print(errors)
end
},
-- finally 代码块
finally
{
-- 最后都会执行到这里
function (ok, errors)
-- 如果try{}中存在异常,ok为true,errors为错误信息,否则为false,errors为try中的返回值
end
}
}
或者只有finally块:
try
{
-- try 代码块
function ()
return "info"
end,
-- finally 代码块
finally
{
-- 由于此try代码没发生异常,因此ok为true,errors为返回值: "info"
function (ok, errors)
end
}
}
处理可以在finally中获取try里面的正常返回值,其实在仅有try的情况下,也是可以获取返回值的:
-- 如果没发生异常,result 为返回值:"xxxx",否则为nil
local result = try
{
function ()
return "xxxx"
end
}
可以看到,这个基于pcall的try-catch-finally异常捕获封装,使用上还是非常灵活的,而且其实现相当的简单
这也充分说明了lua是一门已非常强大灵活,又非常精简的语言。
在xmake的自定义脚本、插件开发中,也是完全基于此异常捕获机制
这样使得扩展脚本的开发非常的精简可读,省去了繁琐的if err ~= nil then返回值判断,在发生错误时,xmake会直接抛出异常进行中断,然后高亮提示详细的错误信息。
例如:
target("test")
set_kind("binary")
add_files("src/*.c")
-- 在编译完ios程序后,对目标程序进行ldid签名
after_build(function (target))
os.run("ldid -S %s", target:targetfile())
end
只需要一行os.run就行了,也不需要返回值判断是否运行成功,因为运行失败后,xmake会自动抛异常,中断程序并且提示错误
如果你想在运行失败后,不直接中断xmake,继续往下运行,可以自己加个try快就行了:
target("test")
set_kind("binary")
add_files("src/*.c")
after_build(function (target))
try
{
function ()
os.run("ldid -S %s", target:targetfile())
end
}
end
如果还想捕获出错信息,可以再加个catch:
target("test")
set_kind("binary")
add_files("src/*.c")
after_build(function (target))
try
{
function ()
os.run("ldid -S %s", target:targetfile())
end,
catch
{
function (errors)
print(errors)
end
}
}
end
不过一般情况下,在xmake中写自定义脚本,是不需要手动加try-catch的,直接调用各种api,出错后让xmake默认的处理程序接管,直接中断就行了。。
最后附上try-catch-finally实现的相关完整源码:
个人主页:TBOOX开源工程
原文出处:http://tboox.org/cn/2016/12/14/try-catch/
使用lua实现try-catch异常捕获的更多相关文章
- TP5 try{}catch{}异常捕获不到 解决办法
问题:TP5用下面的方法, 想要获取抛出的异常捕获不到…… 错误的写法: try{ …… } catch (Exception $e) { echo $e->getMessage(); } 正确 ...
- try catch异常捕获
格式为: try { int i = int.Parse(Console.ReadLine()); //容易发生错误的语句 ...
- Servlet过滤器——异常捕获过滤器
1.概述 介绍如何实现异常捕获过滤器. 2.技术要点 本实例主要是在过滤器Filter的doFilter()方法中,对执行过滤器链的chain的doFilter()语句处添加try…catch异常捕获 ...
- C# 异常捕获机制(Try Catch Finally)
一.C#的异常处理所用到关键字 try 用于检查发生的异常,并帮助发送任何可能的异常. catch 以控制权更大的方式处理错误,可以有多个catch子句. finally 无论是否引发了异常,fina ...
- T-SQL编程中的异常处理-异常捕获(catch)与抛出异常(throw)
本文出处: http://www.cnblogs.com/wy123/p/6743515.html T-SQL编程与应用程序一样,都有异常处理机制,比如异常的捕获与异常的抛出,本文简单介绍异常捕获与异 ...
- T-SQL编程中的异常处理-异常捕获(try catch)与抛出异常(throw)
本文出处: http://www.cnblogs.com/wy123/p/6743515.html T-SQL编程与应用程序一样,都有异常处理机制,比如异常的捕获与异常的抛出(try catch th ...
- C#中的异常捕获机制(try catch finally)
(转自:http://blog.csdn.net/zevin/article/details/6901489) 一.C#的异常处理所用到关键字try 用于检查发生的异常,并帮助发送任何可能的异常.ca ...
- C#中try catch中throw ex和throw方式抛出异常有何不同_异常捕获堆栈丢失问题
前言,最近遇到一个使用try-catch异常捕获后记录一下日志,然后再抛出该异常后,异常堆栈里无法显示准确的堆栈地址的问题? 其实以前也遇到过类似问题,没有重视,这次好好研究了下,并上度娘上找了找 ...
- 异常捕获 崩溃 Bugly ACRC 简介 总结 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
随机推荐
- 使用量产工具合并U盘空间一例
1.问题提出: 朋友拿到一只别人赠送的广告U盘,上面印刷有产品广告.插入电脑后,在系统的磁盘管理中,显示为两块“硬盘”,其中一块“硬盘”中有广告视频.产品介绍等,占用大概6GB,这块“硬盘”中的这 ...
- 解决vuex数据页面刷新后初始化问题
在vue项目的开发中经常会用到vuex来进行数据的存储,然而在开发过程中会出现刷新后页面的vuex的state数据初始化问题!下面是我用过的解决方法 利用storage缓存来实现vuex数据的刷新问题 ...
- tf模型可视化工具
一方面可以用tensorboard来可视化,更方便的是用如下网址: https://lutzroeder.github.io/netron/
- 洛谷 P4665 [BalticOI 2015]Network
洛谷 P4665 [BalticOI 2015]Network 你有一棵 $ n $ 个节点的树,你可以在树上加一些边,使这棵树变成一张无重边.自环的图,且删掉任意一条边它仍然联通.求最少要加多少条边 ...
- vue全家桶是啥?
Vue有著名的全家桶系列,包含了 1,调试插件:可以选择 Chrome 插件 vue Devtool(需要下载工具包).打开控制台选择 vue 面板.也可以选择 Vuex 选项.vuex(http:/ ...
- 微信小程序-坑1-await-async
VM45:1 thirdScriptError sdk uncaught third Error regeneratorRuntime is not defined ReferenceError: r ...
- 使用IDEA自动生成Java实体类
在上一篇帖子里,我们已经通过idea连接上了数据库,这里,通过IDEA自带的功能来根据数据库字段生成POJO 1. 选中一张表,右键--->Scripted Extensions--->选 ...
- linux运维、架构之路-CentOS6.9安装Zabbix3.4.1
一.LAMP环境安装 1.环境 [root@m01 ~]# cat /etc/redhat-release CentOS release 6.9 (Final) [root@m01 ~]# uname ...
- JavaScript正则表达式简介(一)
一.正则表达式 正则表达式Regular Expression,可以简写为regexp.regex或是RE. 正则表达式使用单个字符串来描述或是匹配一系列符合某个句法规则的字符串模型. 按照某种规则去 ...
- CSS盒子模型(框模型)
一.如何理解盒子模型 盒子模型(框模型)是css部分非常重要的一部分知识,CSS在处理网页的时候,认为每个元素都处在一个不可见的盒子中.盒子模型的构想,把所有的元素都想象成盒子,那么对网页进行布局 ...