2022年的 Tcl/Tk 编程入门参考 7.异常处理
学习异常处理部分时,推荐用tclsh来执行。因为在一部分情况下,tclsh的报错内容比wish更详细。
异常处理是一种机制,绝大部分编程语言都有,而且机制都差不多。在实际编程中,经常会出现预料之外的情况,比如说:在批量处理文本文件时,某个文件被系统锁定了;再比如下载文件,网断了。这些特殊情况,会让原本正常的代码,崩溃退出。为了应对各种奇葩的意外情况,编程语言普遍都准备异常处理机制,通过这个机制,即便出现了意外,也能让整个程序继续运行下去。
因为各人思路不一样,在此我只提千万不要干的事情:绝对不要通过异常处理机制去掩盖错误!
Tcl语言通过try和catch两个命令,可以做到在程序运行时不报错,最简单的就是把代码放到catch命令里面,但是这种做法根本没有处理异常,只是在掩盖异常。即使是个人程序,也不要这么干。异常处理机制是用来处理异常的,不是掩盖异常的。
实际上一个没有异常处理的程序并不可怕,因为有问题就报错中止运行了。最可怕的程序就是掩盖异常的程序,我们根本不知道它运行的时候有没有异常发生,结果不可靠,不能被信任。而且越是有经验的程序员写的就越危险,他们的代码99%的情况都按预期运行,那么掩盖的就是那1%的意外,就这1%他自己都说不清楚什么时候会发生,完全没有规律,届时查错能坑死人。
异常变量
每当出错时,TCL语言会将相关信息保存在固定名称的变量里:
errorInfo:TCL会穿透式的追踪错误位置(有代码嵌套时)追踪过程及报错信息会保存在该变量中
errorCode:以列表形式保存的错误信息,包括错误类型和错误代码
catch
catch 命令:执行代码,如出错则捕获错误
catch {代码段} ?信息变量名? ?详细信息(字典)变量名?
例子里yy变量,以字典的形式保存了一堆的报错信息(为便于观看,我分了行)。字典的内容里,errorcode 和 errorInfo 是预设变量。
code 1表示报错了,如果正常运行,code就是0。
level条目的值在绝大多数情况下都是0,只有在代码段以return语句返回时,才会是其它值。
errorline 记录出错位置的行号
errorstack 记录的是堆栈的跟踪信息。本例的 INNER 表示内部错误,其它值请大家参考官方文档。
error
error 报错消息 ?errorInfo内容? ?errorCode内容?
手动生成一个异常,并且可以选择将指定内容存放于errorInfo、errorCode变量中
throw
手动生成与Tcl解释器内置错误相同的异常。该命令与error的区别:Tcl语言解释器(tclsh、wish)报错信息都属于内置异常(有固定的类型和提示信息),而error生成的异常并不属于内置异常。throw可以生成与Tcl语言解释器相同的异常,所以官方文档里称其为"机器可读"的异常。
throw 错误类型 报错消息
😳这个命令可以搭配后面介绍的try trap命令,手动生成某种类型的异常,然后再对这种类型进行处理(然而实事求是的说,这也太繁琐了,我宁可把代码段拆分,也不会去干这么摧残发根的事)
try
8.6版新增命令。尝试运行代码段,根据情况进行对应处理,与其它语言try函数类似。
在TCL/TK安装目录 \lib\tcllib1.x\try 下面,有用纯TCL语言写的 try 命令向下兼容版。
try {代码段} 处理部分 ?finally {代码段}?
虽然"处理部分"和finally {代码段}都可以省略,但这种情况下try命令没有任何意义,所以事实上try必须至少搭配一个后续处理代码段。
异常处理 on、trap
try命令的异常处理部分有两种形式,都跟switch命令类似,以匹配执行情况来进行对应的处理。官方文档里是以trap形式来举例的,那我就以on为主来介绍一下。
on的用法是以运行结果标志为基准,进行对应的处理。
on 运行结果标志 变量名列表 {处理代码段}
运行结果一共有五种情况:正常运行、出错、return、break、continue。这5种情况的标识,即可以用数字的0~4来表示,也可用英文单词来表示,即:0-ok, 1-error, 2-return, 3-break, 4-continue
变量名列表:如果只给出一个变量名,这个变量就保存try命令代码段执行的结果。如果给出了两个变量名,第二变量里就以字典的形式,保存一堆的运行结果的信息,跟catch命令的“详细信息”内容是一样的。
trap 根据错误类型执行代码段。就是前面 throw 命令里提到的,Tcl各种内置错误
trap 错误类型 变量名列表 {处理代码段}
本例中完整异常类型为 TCL LOOKUP COMMAND。其中"TCL"是一种大类型,其中包括"LOOKUP",而"COMMAND"是更具体的子类型。当设置为 trap {TCL}时,表示所有归为"TCL"类的异常都这样处理。
更多内置异常类型请去官网搜索,如果文档里没有就去官方wiki翻翻
finally
finally {代码段} :无论try结果如何,都会执行代码段,除非退出TCL解释器
更多try命令介绍,可以参考wiki内容:wiki.tcl-lang.org/page/try
return
还有一种返回异常的方式是通过return命令,更准确的说是返回状态。catch和try命令以字典的形式保存的异常"详细信息",也可以用于return命令。
return -code 状态标识(0-ok, 1-error, 2-return, 3-break, 4-continue)
return -options $异常详细信息 $提示信息
更多信息参考return的官方文档